home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-09-28 | 147.7 KB | 4,754 lines | [TEXT/CWIE] |
- /*
- File: NetworkSetupHelpers.c
-
- Contains: High-level network preference routines.
-
- Written by: Quinn
-
- Copyright: Copyright © 1998 by Apple Computer, Inc., all rights reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
-
- <21> 18/1/00 Quinn Further updates for the new Network Setup header file.
- <20> 17/1/00 Quinn Updates for latest Network Setup headers.
- <19> 6/1/00 Quinn Updated NSHEncodeRemotePassword to use the Network Setup routine
- OTCfgEncrypt if it's available (Mac OS 9.0 and higher).
- <18> 7/12/99 Quinn AOL registers as an Ethernet device, even though it supports
- dialling. They will fix this, but I've added a special case to
- handle it here as well.
- <17> 19/10/99 Quinn Fix embarrassing spelling error.
- <16> 12/10/99 Quinn Fixed bug in the 'isdm' stage of
- BuildPackedPrefsFromTCPv4ConfigurationDigest where, if no
- fSearchDomains was specified, we would set up
- kTCPRoutersListAttr instead of kTCPDomainsListAttr. Thanks to
- John Norstad.
- <15> 13/9/99 Quinn Fix bug where CreateConfigurationDatabase wasn't setting up
- cookie4 correctly. Thanks for Tom Bayley.
- <14> 13/9/99 Quinn Fix bug in creating MacIP configurations. Thanks to Thomas
- Weisbach for the fix.
- <13> 13/9/99 Quinn Implement DHCPRelease.
- <12> 26/5/99 Quinn Use cookie4 in NSHConfigurationEntry. Implement support for
- Internet setup routines on legacy files. Improved code sharing
- between database and legacy files. Fixed bug in
- BuildPackedPrefsFromModemConfigurationDigest; duplicated 'mdpw'
- prefs.
- <11> 7/5/99 Quinn This "redux" word, I don't think it means what you think it
- means.
- <10> 22/4/99 Quinn Added code to encode Remote Access passwords. Also reworked how
- the default 'lcp ' preference was generated, using Network Setup
- if possible.
- <9> 21/4/99 Quinn Added massive amounts of code to create, duplicate, get, set,
- delete and rename configurations for TCP/IP, Remote Access, and
- Modem. Also fixed a bug in NSHIsAppleTalkActive where it was
- return an assembly Boolean (0/0xff) rather than a C Boolean
- (0/1).
- <8> 16/3/99 Quinn Fixed one-based array problem in GetConfigurationListFromFile.
- <7> 10/11/98 Quinn Fix = vs == in an assert.
- <6> 10/11/98 Quinn Convert "MorePrefix.h" to "MoreSetup.h".
- <5> 9/11/98 Quinn AppleTalk on/off support.
- <4> 9/11/98 Quinn Add "TCP will dial" code.
- <3> 5/11/98 Quinn Use MoreAssertQ instead of MoreAssert.
- <2> 5/11/98 Quinn Fix header.
- <1> 5/11/98 Quinn First checked in.
- */
-
- /////////////////////////////////////////////////////////////////
-
- // MoreIsBetter Setup
-
- #include "MoreSetup.h"
-
- // Mac OS Interfaces
-
- #include <Types.h>
- #include <Files.h>
- #include <Errors.h>
- #include <Folders.h>
- #include <Resources.h>
- #include <Gestalt.h>
- #include <CodeFragments.h>
- #include <NetworkSetup.h>
- #include <OpenTptLinks.h>
- #include <OpenTptConfig.h>
- #include <Traps.h>
-
- // MIB Prototypes (stuff that should be in Universal Interfaces)
-
- #include "RemoteAccessInterface.h"
-
- // MIB Prototypes (stuff that should be in Universal Interfaces)
-
- #include "MoreTextUtils.h"
- #include "MoreInterfaceLib.h"
- #include "MoreNetworkSetup.h"
- #include "OldOTConfigLib.h"
-
- // Our Prototypes
-
- #include "NetworkSetupHelpers.h"
-
- /////////////////////////////////////////////////////////////////
- // Testing Parameters
-
- enum {
-
- // Throw this switch if you want to debug the direct preference
- // file access code on a machine with Network Setup installed.
-
- kUseNetworkSetup = true,
-
- // If you set kUseInetInterfaceInfo to false, NSHTCPWillDial will not
- // use the heuristic of "if the TCP/IP stack is loaded, it's safe
- // to open an endpoint". This is especially useful when debugging.
-
- kUseInetInterfaceInfo = true
-
- };
-
- /////////////////////////////////////////////////////////////////
-
- extern pascal ItemCount NSHCountConfigurationList(NSHConfigurationListHandle configList)
- // See comments in interface part.
- {
- return GetHandleSize( (Handle) configList ) / sizeof(NSHConfigurationEntry);
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Configuration List using Database -----
-
- // Parameter structure for SetterIterator.
-
- struct TypeAndClassParam {
- OSType fType;
- OSType fClass;
- Boolean found;
- CfgEntityRef *currentEntity;
- };
- typedef struct TypeAndClassParam TypeAndClassParam;
-
- static pascal void TypeAndClassIterator(const MNSDatabaseRef *ref, CfgSetsElement *thisElement, void *p)
- // This routine is used as a callback for MNSIterateSet.
- // It looks for the entity specified by the fType and fClass
- // fields of the param, and puts its entityRef into the
- // variable pointed to by the currentEntity field of param.
- {
- TypeAndClassParam *param;
-
- param = (TypeAndClassParam *) p;
-
- MoreAssertQ(MNSValidDatabase(ref));
- MoreAssertQ(thisElement != nil);
- MoreAssertQ(param != nil);
- MoreAssertQ(param->currentEntity != nil);
-
- if (thisElement->fEntityInfo.fClass == param->fClass && thisElement->fEntityInfo.fType == param->fType) {
- MoreAssertQ( ! param->found );
- param->found = true;
- *(param->currentEntity) = thisElement->fEntityRef;
- }
- }
-
- enum {
- kNoCurrentConnectionErr = -6
- };
-
- static OSStatus FindCurrentConnection(const MNSDatabaseRef *ref, OSType protocol, CfgEntityRef *currentEntity)
- // This routine finds the current connection entity for the specified
- // protocol in the active set, returning it in currentEntity.
- {
- OSStatus err;
- CfgEntityRef activeSet;
- TypeAndClassParam param;
-
- MoreAssertQ(MNSValidDatabase(ref));
- MoreAssertQ(currentEntity != nil);
-
- param.fClass = kOTCfgClassNetworkConnection;
- param.fType = protocol;
- param.found = false;
- param.currentEntity = currentEntity;
-
- err = MNSFindActiveSet(ref, &activeSet);
- if (err == noErr) {
- err = MNSIterateSet(ref, &activeSet, TypeAndClassIterator, ¶m, false);
- }
- if (err == noErr) {
- if (param.found) {
- // Set preferences contain entities from weird areas because
- // of the way the database is committed. We can safely fix
- // that up here. I discussed with the Network Setup engineer
- // and he reassured me that this was cool -- Quinn, 9 Nov 1998
-
- currentEntity->fLoc = ref->area;
- } else {
- err = kNoCurrentConnectionErr;
- }
- }
-
- return err;
- }
-
- static OSStatus AddEntityToConfigurationList(const MNSDatabaseRef *ref,
- const CfgEntityRef *entity,
- const CfgEntityInfo *entityInfo,
- OSType protocol,
- NSHConfigurationListHandle configList)
- // This routines adds the entity specified by entity and entityInfo
- // in the database specified by ref to the configList.
- {
- OSStatus err;
- NSHConfigurationEntry thisEntry;
- StringPtr entityName;
- ByteCount junkSize;
-
- MoreAssertQ(configList != nil);
- MoreAssertQ(MNSValidDatabase(ref));
- MoreAssertQ(entity != nil);
- MoreAssertQ(entityInfo != nil);
-
- // Get the user-visible name from the configuration, which is
- // stored in the 'pnam' preferences.
-
- entityName = nil;
- err = MNSGetPref(ref, entity, kOTCfgUserVisibleNamePref, &entityName, &junkSize);
- if (err == noErr) {
- MoreAssertQ(junkSize == (entityName[0] + 1));
- BlockMoveData(entityName, &thisEntry.name, entityName[0] + 1);
- thisEntry.selected = false;
- thisEntry.cookie = 0;
- thisEntry.cookie2 = *entity;
- thisEntry.cookie3 = *entityInfo;
- thisEntry.cookie4 = protocol;
- }
-
- if (err == noErr) {
- err = PtrAndHand(&thisEntry, (Handle) configList, sizeof(thisEntry));
- }
-
- // Clean up.
-
- if (entityName != nil) {
- DisposePtr( (Ptr) entityName);
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- // Parameter structure for SetterIterator.
-
- struct SetterParam {
- OSType fType;
- OSType fClass;
- const CfgEntityRef *chosenConfig;
- const CfgEntityInfo *chosenConfigInfo;
- };
- typedef struct SetterParam SetterParam;
-
- static pascal void SetterIterator(const MNSDatabaseRef *ref, CfgSetsElement *thisElement, void *p)
- // This routine is used as a callback for MNSIterateSet.
- // It looks for the entity specified by the fType and fClass
- // fields of the param, and replaces it with the chosen
- // entity and info from the param. It expects that the caller
- // of MNSIterateSet has specified writeAfterIterate so that
- // the changes get written back to the set.
- {
- SetterParam *param;
-
- param = (SetterParam *) p;
-
- MoreAssertQ(MNSValidDatabase(ref));
- MoreAssertQ(MNSDatabaseWritable(ref));
- MoreAssertQ(thisElement != nil);
- MoreAssertQ(param != nil);
- MoreAssertQ(param->chosenConfig != nil);
- MoreAssertQ(param->chosenConfigInfo != nil);
-
- if (thisElement->fEntityInfo.fClass == param->fClass && thisElement->fEntityInfo.fType == param->fType) {
- thisElement->fEntityRef = *param->chosenConfig;
- thisElement->fEntityInfo = *param->chosenConfigInfo;
- }
- }
-
- static OSStatus GetConfigurationListFromDatabase(OSType protocol, NSHConfigurationListHandle configList)
- // Implementation of NSHGetConfigurationList which uses the Network Setup
- // database. See NSHGetConfigurationList's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabaseRef ref;
- ItemCount entityCount;
- CfgEntityRef *entityRefs;
- CfgEntityInfo *entityInfos;
- CfgEntityRef activeConn;
- ItemCount i;
-
- entityRefs = nil;
- entityInfos = nil;
-
- err = MNSOpenDatabase(&ref, false);
- if (err == noErr) {
-
- // Find all the network connection entities for this protocol.
-
- err = MNSGetEntitiesList(&ref,
- kOTCfgClassNetworkConnection, protocol,
- &entityCount,
- &entityRefs,
- &entityInfos);
-
- // Add each to the list of possible connections.
-
- if (err == noErr) {
- for (i = 0; i < entityCount; i++) {
- err = AddEntityToConfigurationList(&ref, &entityRefs[i], &entityInfos[i], protocol, configList);
- }
- }
-
- // Find the current configuration and mark it as selected
- // in the list.
-
- if (err == noErr) {
- err = FindCurrentConnection(&ref, protocol, &activeConn);
- }
- if (err == noErr) {
- for (i = 0; i < entityCount; i++) {
- if ( OTCfgIsSameEntityRef(&activeConn, &(*configList)[i].cookie2, kOTCfgIgnoreArea) ) {
- (*configList)[i].selected = true;
- }
- }
- }
-
- err2 = MNSCloseDatabase(&ref, false);
- if (err == noErr) {
- err = err2;
- }
- }
-
- // Clean up.
-
- if (entityInfos != nil) {
- DisposePtr( (Ptr) entityInfos);
- MoreAssertQ(MemError() == noErr);
- }
- if (entityRefs != nil) {
- DisposePtr( (Ptr) entityRefs);
- MoreAssertQ(MemError() == noErr);
- }
- return err;
- }
-
- static OSStatus SelectConfigurationFromDatabase(const NSHConfigurationEntry *chosenEntry)
- // Implementation of NSHSelectConfiguration which uses the Network Setup
- // database. See NSHSelectConfiguration's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabaseRef ref;
- CfgEntityRef activeSet;
- SetterParam param;
-
- err = MNSOpenDatabase(&ref, true);
- if (err == noErr) {
- param.fClass = kOTCfgClassNetworkConnection;
- param.fType = chosenEntry->cookie4;
- param.chosenConfig = &chosenEntry->cookie2;
- param.chosenConfigInfo = &chosenEntry->cookie3;
-
- err = MNSFindActiveSet(&ref, &activeSet);
- if (err == noErr) {
- err = MNSIterateSet(&ref, &activeSet, SetterIterator, ¶m, true);
- }
-
- err2 = MNSCloseDatabase(&ref, err == noErr);
- if (err == noErr) {
- err = err2;
- }
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Configuration List using File -----
-
- static OSStatus SearchFolder(SInt16 vRefNum, SInt32 dirID,
- OSType typeToSearchFor, OSType creatorToSearchFor,
- FSSpec *fss)
- // Search a particular folder for a file of a particular
- // type and creator. If it's found, return an FSSpec to
- // the file. If it's not found, return an error.
- {
- OSStatus err;
- Boolean found;
- SInt16 index;
- HParamBlockRec pb;
-
- MoreAssertQ(fss != nil);
-
- fss->vRefNum = vRefNum;
- fss->parID = dirID;
-
- found = false;
- index = 1;
- do {
- pb.fileParam.ioVRefNum = vRefNum;
- pb.fileParam.ioDirID = dirID;
- pb.fileParam.ioNamePtr = fss->name;
- pb.fileParam.ioFDirIndex = index;
- err = PBHGetFInfoSync(&pb);
- if (err == noErr) {
- found = ( pb.fileParam.ioFlFndrInfo.fdType == typeToSearchFor &&
- pb.fileParam.ioFlFndrInfo.fdCreator == creatorToSearchFor );
- }
- index += 1;
- } while (err == noErr & ! found);
-
- return err;
- }
-
- enum {
- kOTNetworkPrefFileType = 'pref',
- kOTTCPPrefFileCreator = 'ztcp',
- kOTAppleTalkPrefFileCreator = 'atdv',
-
- kModemPrefFileType = 'mdpf',
- kModemPrefFileCreator = 'modm',
-
- kRemotePrefFileType = 'lzcn',
- kRemotePrefFileCreator = 'rmot'
- };
-
- static OSStatus FindNetworkPrefFile(OSType protocol, FSSpec *fss)
- // This routine scans the Preferences folder looking
- // for the preferences for the given network protocol.
- // Scans are done by file type and creator to avoid
- // problems on localised systems.
- {
- OSStatus err;
- Boolean searchSubFolders;
- OSType typeToSearchFor;
- OSType creatorToSearchFor;
- SInt16 prefFolderVRefNum;
- SInt32 prefFolderDirID;
-
- // Set up the file type and creator based on the protocol.
-
- searchSubFolders = false;
- switch (protocol) {
- case kOTCfgTypeTCPv4:
- typeToSearchFor = kOTNetworkPrefFileType;
- creatorToSearchFor = kOTTCPPrefFileCreator;
- break;
- case kOTCfgTypeAppleTalk:
- typeToSearchFor = kOTNetworkPrefFileType;
- creatorToSearchFor = kOTAppleTalkPrefFileCreator;
- break;
- case kOTCfgTypeRemote:
- typeToSearchFor = kRemotePrefFileType;
- creatorToSearchFor = kRemotePrefFileCreator;
- searchSubFolders = true;
- break;
- case kOTCfgTypeModem:
- typeToSearchFor = kModemPrefFileType;
- creatorToSearchFor = kModemPrefFileCreator;
- break;
- default:
- MoreAssertQ(false);
- break;
- }
-
- // Search the Preferences folder for a file with that type and creator.
-
- err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder, &prefFolderVRefNum, &prefFolderDirID);
- if (err == noErr) {
-
- // The Remote Access preference file is stored in a folder within
- // the preferences folder. We can't hard wire the name "Remote Access"
- // because the name is localised. Instead, we search all the folders
- // within the preferences folder for the file. In all other cases,
- // we just search the preferences folder for the file.
-
- if (searchSubFolders) {
- Boolean found;
- CInfoPBRec cpb;
- SInt16 index;
-
- found = false;
- index = 1;
- do {
- cpb.dirInfo.ioVRefNum = prefFolderVRefNum;
- cpb.dirInfo.ioDrDirID = prefFolderDirID;
- cpb.dirInfo.ioNamePtr = nil;
- cpb.dirInfo.ioFDirIndex = index;
- err = PBGetCatInfoSync(&cpb);
- if (err == noErr && ((cpb.dirInfo.ioFlAttrib & ioDirMask) != 0)) {
- found = ( SearchFolder(prefFolderVRefNum, cpb.dirInfo.ioDrDirID,
- typeToSearchFor, creatorToSearchFor,
- fss) == noErr);
- }
- index += 1;
- } while (err == noErr & ! found);
- } else {
- err = SearchFolder(prefFolderVRefNum, prefFolderDirID,
- typeToSearchFor, creatorToSearchFor,
- fss);
- }
- }
- return err;
- }
-
- static OSStatus CheckResError(void *testH)
- // A trivial wrapper routine for ResError,
- // which is too lame to report an error code
- // in all cases when GetResource fails.
- {
- OSStatus err;
-
- err = ResError();
- if (err == noErr && testH == nil) {
- err = resNotFound;
- }
- return err;
- }
-
- static OSStatus OpenNetworkPrefFile(OSType protocol, SInt8 permission,
- SInt16 *oldResFile, SInt16 *networkResFile)
- // Opens the legacy preference file for the given protocol with
- // the specified permission (typicallly fsRdPerm or fsRdWrPerm).
- // Returns the previous CurResFile and the refnum of the new
- // file, both of which you pass to CloseNetworkPrefFile to clean up
- // the open.
- {
- OSStatus err;
- FSSpec fss;
-
- MoreAssertQ(oldResFile != nil);
- MoreAssertQ(networkResFile != nil);
-
- *oldResFile = CurResFile();
- err = FindNetworkPrefFile(protocol, &fss);
- if (err == noErr) {
- if (permission == fsRdWrPerm) {
- // ••• Gotcha •••
- // Really need to be careful here because it's possible
- // that fss is open in our current resource chain.
- // See DTS Technote 1120 "Opening Resource Files Twice Considered
- // Hard?" for details.
- //
- // <http://developer.apple.com/technotes/tn/tn1120.html>
- //
- // I'll probably put real code to detect and handle this into
- // MoreResources eventually; in the mean time, you have to live
- // with the limitation that you can't use this library when
- // a legacy preference file might be open in your resource chain.
- // -- Quinn, 9 Nov 1998
- }
-
- // SetResLoad to false around the open to avoid bringing
- // any preload resources in the file into memory.
-
- SetResLoad(false);
- *networkResFile = FSpOpenResFile(&fss, permission);
- err = ResError();
- SetResLoad(true);
- }
-
- // If we error, setup the outputs to values we can use to
- // detect client logic errors in CloseNetworkPrefFile.
-
- if (err != noErr) {
- *oldResFile = 0;
- *networkResFile = 0;
- }
-
- return err;
- }
-
- static OSStatus CloseNetworkPrefFile(SInt16 oldResFile, SInt16 networkResFile)
- // Closes the legacy preference file you opened using OpenNetworkPrefFile.
- {
- OSStatus err;
-
- MoreAssertQ(oldResFile != 0);
- MoreAssertQ(networkResFile != 0);
-
- CloseResFile(networkResFile);
- err = ResError();
- if (err == noErr) {
- UseResFile(oldResFile);
- MoreAssertQ(ResError() == noErr);
- }
- return err;
- }
-
- static OSStatus CommitChangesToPrefFile(OSType protocol, SInt16 refNum, SInt16 config)
- // This routine represents the magic that allows you to force OT
- // to notice a configuration file change without rebooting. It uses
- // some previously undocumented routines, the glue for which is provided
- // as part of this sample. This routine is called by any direct file
- // modification code which modifies the active configuration.
- //
- // IMPORTANT:
- // The only reason it's safe to document these routines now is that we
- // know that they work on all old versions of OT, and new versions of OT
- // include the Network Setup library which allows you to change network
- // preferences without any of this hackery. Never ship a product that
- // relies on these routines that doesn't also use Network Setup if it's
- // available.
- {
- OSStatus err;
-
- err = noErr;
- switch (protocol) {
- case kOTCfgTypeTCPv4:
- if ( TCPCheckChangeConfigurationConsequences(refNum, config) == kMustReboot ) {
- err = -7;
- }
- if ( err == noErr ) {
- err = TCPChangeConfiguration(refNum, config);
- }
- break;
- case kOTCfgTypeAppleTalk:
- if ( ATCheckChangeConfigurationConsequences(refNum, config) == kMustReboot ) {
- err = -7;
- }
- if ( err == noErr ) {
- err = ATChangeConfiguration(refNum, config);
- }
- break;
- case kOTCfgTypeRemote:
- case kOTCfgTypeModem:
- {
- Handle currentConfigResourceH;
-
- // For Remote and Modem, we directly munge the preferences
- // file. There's no way to tweak these protocol stacks
- // to get them to recognise the updated file. Instead,
- // they'll pick up the preferences the next time you connect.
- // Hmmm, except for ARA Personal Server, for which we
- // have no solution at the moment.
-
- currentConfigResourceH = Get1Resource(kOTCfgCompatSelectedPref, 1);
- err = CheckResError(currentConfigResourceH);
-
- if (err == noErr && GetHandleSize(currentConfigResourceH) != sizeof(SInt16) ) {
- // Assert: 'ccfg' is of the wrong size
- MoreAssertQ(false);
- err = -1;
- } else {
- **(SInt16 **)currentConfigResourceH = config;
- ChangedResource(currentConfigResourceH);
- err = ResError();
- }
- }
- break;
- default:
- MoreAssertQ(false);
- err = -7;
- break;
- }
- return err;
- }
-
- static OSStatus GetCurrentConfigFromPrefFile(SInt16 *config)
- // This routine returns the resource ID of the current
- // configurator in a legacy preferences file.
- {
- OSStatus err;
- Handle currentConfigResourceH;
-
- MoreAssertQ(config != nil);
-
- currentConfigResourceH = Get1Resource(kOTCfgCompatSelectedPref, 1);
- err = CheckResError(currentConfigResourceH);
-
- if (err == noErr && GetHandleSize(currentConfigResourceH) != sizeof(SInt16) ) {
- // Assert: 'ccfg' is of the wrong size
- MoreAssertQ(false);
- err = -1;
- } else {
- *config = **(SInt16 **)currentConfigResourceH;
- }
- return err;
- }
-
- static OSStatus AddResourceToConfigurationList(OSType protocol, Handle cnamHandle, NSHConfigurationListHandle configList)
- // Given a handle to a 'cnam' resource, generate a
- // NSHConfigurationEntry and append it to the list
- // of configurations.
- {
- OSStatus err;
- NSHConfigurationEntry thisEntry;
- SInt16 cnamID;
- ResType junkType;
-
- GetResInfo(cnamHandle, &cnamID, &junkType, thisEntry.name);
- MoreAssertQ(ResError() == noErr);
- MoreAssertQ(junkType == kOTCfgCompatNamePref);
- thisEntry.selected = false;
- thisEntry.cookie = cnamID;
- OTMemzero(&thisEntry.cookie2, sizeof(thisEntry.cookie2));
- OTMemzero(&thisEntry.cookie3, sizeof(thisEntry.cookie3));
- thisEntry.cookie4 = protocol;
-
- err = PtrAndHand(&thisEntry, (Handle) configList, sizeof(thisEntry));
- return err;
- }
-
- static OSStatus GetConfigurationListFromFile(OSType protocol, NSHConfigurationListHandle configList)
- // Implementation of NSHGetConfigurationList which uses the legacy
- // preference files. See NSHGetConfigurationList's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- Handle cnamHandle;
- SInt16 refNum;
- SInt16 resCount;
- SInt16 i;
- SInt16 currentConfigID;
- SInt16 oldResFile;
-
- err = OpenNetworkPrefFile(protocol, fsRdPerm, &oldResFile, &refNum);
- if (err == noErr) {
- resCount = Count1Resources(kOTCfgCompatNamePref);
-
- for (i = 1; i <= resCount; i++) {
- SetResLoad(false);
- cnamHandle = Get1IndResource(kOTCfgCompatNamePref, i);
- err = CheckResError(cnamHandle);
- SetResLoad(true);
-
- if (err == noErr) {
- err = AddResourceToConfigurationList(protocol, cnamHandle, configList);
- }
-
- // Don't need to release the resource because CloseResFile will
- // clean it up.
-
- if (err != noErr) {
- break;
- }
- }
-
- if (err == noErr) {
- err = GetCurrentConfigFromPrefFile(¤tConfigID);
- }
- if (err == noErr) {
- for (i = 0; i < resCount; i++) {
- if ( (*configList)[i].cookie == currentConfigID ) {
- (*configList)[i].selected = true;
- }
- }
- }
-
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- return err;
- }
-
- static OSStatus SelectConfigurationFromFile(const NSHConfigurationEntry *chosenEntry)
- // Implementation of NSHGetConfigurationList which uses the legacy
- // preference files. See NSHGetConfigurationList's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- SInt16 refNum;
- SInt16 oldResFile;
-
- err = OpenNetworkPrefFile(chosenEntry->cookie4, fsRdWrPerm, &oldResFile, &refNum);
- if (err == noErr) {
- err = CommitChangesToPrefFile(chosenEntry->cookie4, refNum, chosenEntry->cookie);
-
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Configuration List Abstraction ------
-
- extern pascal OSStatus NSHGetConfigurationList(OSType protocol, NSHConfigurationListHandle configList)
- // See comments in interface part.
- {
- OSStatus err;
-
- SetHandleSize( (Handle) configList, 0);
- MoreAssertQ(MemError() == noErr);
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = GetConfigurationListFromDatabase(protocol, configList);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = GetConfigurationListFromFile(protocol, configList);
- }
- return err;
- }
-
- extern pascal OSStatus NSHSelectConfiguration(const NSHConfigurationEntry *chosenEntry)
- // See comments in interface part.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = SelectConfigurationFromDatabase(chosenEntry);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = SelectConfigurationFromFile(chosenEntry);
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Internet Setup Documentation ------
-
- /*
- The mapping from NSHTCPv4ConfigurationDigest fields to preferences
- is as follows:
-
- fProtocol -> kOTCfgTypeTCPv4
- fConfigName; -> 'pnam'
- fPortRef; -> 'port', 'iitf'
- fUnloadAttr; -> 'unld'
- fDNSServerList; -> 'idns'
- fLocalDomain; -> 'ihst'
- fAdminDomain; -> 'ihst'
- fConfigMethod; -> 'iitf'
- fIPAddress; -> 'iitf'
- fSubnetMask; -> 'iitf'
- fAppleTalkZone; -> 'iitf'
- fFraming; -> 'iitf'
- fSearchDomains; -> 'isdm'
- fRouterList; -> 'irte'
-
- The reverse mapping, from preference to NSHTCPv4ConfigurationDigest field,
- is:
-
- 'pnam' -> fConfigName
- 'port' -> UserVisibleName(fPortRef) -- or "AppleTalk (Mac IP)", localisation?
- 'pwrd' -> "\p"
- 'cvrs' -> 1
- 'prot' -> "tcp"
- 'unld' -> fUnloadAttr
- 'idns' -> GetHandleSize(fDNSServerList) div sizeof(InetHost), fDNSServerList;
- 'ihst' -> 1, fLocalDomain, fAdminDomain (packed)
- 'iitf' -> 1, fConfigMethod, fIPAddress, fSubnetMask, fAppleTalkZone, PortName(fPortRef), fModuleName(fPortRef), fFraming
- 'dtyp' -> DeviceType(fPortRef) -- or kOTNoDevice for MacIP
- 'stng' -> $00 * 25
- 'isdm' -> fSearchDomains
- 'irte' -> fRouterList, padded appropriately
- */
-
- /*
- Mapping from NSHRemoteConfigurationDigest fields to preference types:
-
- fProtocol; kOTCfgTypeRemote
- fConfigName; -> 'pnam'
- fGuestLogin -> 'conn' (isGuest)
- fPasswordValid -> 'conn' (passwordSaved)
- fUserName; -> 'cusr'
- fPassword; -> 'pass'
- fPhoneNumber; -> 'cadr', 'conn' (addressLength)
- fRedialMode; -> 'cdia' (dialMode)
- fRedialTimes; -> 'cdia' (redialTries)
- fRedialDelay; -> 'cdia' (redialDelay)
- fAlternatePhoneNumber; -> 'cead'
- fVerboseLogging; -> 'logo' (logLevel)
- fFlashIconWhileConnected; -> 'conn' (flashConnectedIcon)
- fPromptToRemainConnected; -> 'conn' (issueConnectedReminders)
- fPromptInterval; -> 'conn' (reminderMinutes)
- fDisconnectIfIdle; -> 'ipcp' (idleTimerEnabled)
- fDisconnectInterval; -> 'ipcp' (idleTimerMilliseconds)
- fSerialProtocol; -> 'conn' (serialProtocolMode)
- fPPPConnectAutomatically; -> 'cmsc' (isAutoConnect)
- fPPPAllowModemCompression; -> 'conn' (allowModemDataCompression)
- fPPPAllowTCPIPHeaderCompression; -> 'ipcp' (compressTCPHeaders)
- fPPPConnectMode; -> 'conn' (chatMode)
- fPPPConnectScriptName; -> 'conn' (chatScriptName)
- fPPPConnectScript; -> 'ccha', 'conn' (chatScriptLength)
-
- fixed value (see below) -> 'lcp '
- $0002 $0003 "Script" [36] -> 'arap'
- $0002 $0003 $00 * 596 -> 'x25 '
- $0002 $0003 $00 * 68 -> 'dass'
- $00010000 $00000001 $00 * 256 -> 'usmd'
- $0002 $0003 $00 * 64 -> 'clks'
-
- This is the mapping from preference type to NSHRemoteConfigurationDigest field.
-
- 'pnam' -> fConfigName
- 'cmsc' -> fPPPConnectAutomatically
- 'conn' -> fGuestLogin, fPasswordValid, fPhoneNumber, fFlashIconWhileConnected, fPromptToRemainConnected, fPromptInterval, fSerialProtocol, fPPPAllowModemCompression, fPPPConnectMode, fPPPConnectScriptName, fPPPConnectScript
- 'cusr' -> fUserName
- 'pass' -> fPassword
- 'cdia' -> fRedialMode, fRedialTimes, fRedialDelay
- 'ipcp' -> fDisconnectIfIdle, fDisconnectInterval, fPPPAllowTCPIPHeaderCompression
- 'logo' -> fVerboseLogging
- 'cadr' -> fPhoneNumber
- 'cead' -> fAlternatePhoneNumber
- 'ccha' -> fPPPConnectScript
-
- 'usmd' -> junk
- 'clks' -> junk
- 'lcp ' -> junk
- 'arap' -> junk
- 'dass' -> junk
- 'x25 ' -> junk
- 'term' -> junk
- 'cnam' -> junk
- 'resn' -> junk
- 'resi' -> junk
-
- */
-
- // This fixed value for the Remote Access 'lcp ' preference is only used if
- // OTCfgGetDefault is not available.
-
- static UInt8 gRemoteLCPValue[108] = {
- 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x63, 0x72, 0x69,
- 0x70, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0A,
- 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x05, 0xDC, 0x00, 0x00, 0x11, 0x94, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
-
- /*
- This is the mapping from preference type to NSHModemConfigurationDigest field.
-
- 'pnam' -> fConfigName
- 'ccl ' -> fPortRef, fModemScript, fDialToneMode, fSpeakerOn, fPulseDial, fHintPortName
- 'lkmd' -> $00000001 + $00000000 * 4
- 'mdpw' -> $00 * 256
-
- 'cnam' -> junk
- 'resn' -> junk
- 'resi' -> junk
- */
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Packed Pref Builder/Writer Infrastructure ------
-
- // All the code that manipulates groups of preferences, ie an entity
- // in a Network Setup sense, uses "packed preferences". This is
- // a group of preferences packed into a handle. Each preference
- // contains a header of its type (OSType) and its data size (ByteCount),
- // not including the header itself. The handle is terminated by
- // an entry with a null preference type.
- //
- // The following routines are an easy way to build and parse these
- // packed preferences. The key focus here was to minimise error
- // checked. So when you build a packed preference, all the checking
- // is done inside these helper routines and you only have to check
- // for errors at the end. Similarly, when you parse a packed preference
- // handle, you know it was built successfully so you can rely on its
- // structure.
- //
- // You typically use these routines in the following way. First,
- // call BuilderNew to initialise the PrefBuilderState record. Then
- // call BuilderNewPref to add a new preference to the handle. If
- // necessary, you can also call BuilderAddPrefData to add extra
- // data to the most recently added preference. Finally, call
- // BuilderDone to extract the packed preference handle, or obtain
- // any error that might have happened while building.
-
- // When building a packed preference, the following state record
- // is used to keep track of what's going on.
-
- struct PrefBuilderState {
- Handle prefData; // handle of packed preference itself, or nil if we got an error somewhere
- OSStatus latchedError; // if an error occured, this field is used to store it until BuilderDone is called
- ByteCount offsetToMostRecentPrefSize; // offset to most recent pref size value,
- // allows BuilderAddPrefData to look back in the handle and bump this size
- };
- typedef struct PrefBuilderState PrefBuilderState;
-
- static void BuilderError(PrefBuilderState *state, OSStatus errNum)
- // This routine is called when an error happens while building.
- // It disposes of the packed preference handle (which ensures
- // that no more building is done) and latches the error where
- // BuilderDone can find it.
- {
- DisposeHandle(state->prefData);
- MoreAssertQ(MemError() == noErr);
- state->prefData = nil;
- state->latchedError = errNum;
- }
-
- static void BuilderNew(PrefBuilderState *state)
- // Initialise the builder state record. See above for
- // this routines place in the big picture. If you call
- // this routine, you must also call BuilderDone to clean
- // up the builder (ie dispose of the handle and recover
- // the latched error code).
- {
- OSStatus err;
-
- state->latchedError = noErr;
- state->offsetToMostRecentPrefSize = 0;
- state->prefData = NewHandle(0);
- err = MemError();
- if (err != noErr) {
- BuilderError(state, err);
- }
- }
-
- static void BuilderAddPrefData(PrefBuilderState *state, const void *data, ByteCount size)
- // Add preference data, described by data and size, to the previous
- // preference added to the builder. It's an error to call this without
- // first calling BuilderNewPref.
- {
- OSStatus err;
-
- if (state->prefData != nil) {
-
- // If this assert fires, it means you've called this routine without first calling BuilderNewPref.
-
- MoreAssertQ(state->offsetToMostRecentPrefSize != 0);
-
- // Add the data to the preference handle.
-
- err = PtrAndHand(data, state->prefData, size);
-
- // Reach back into the preference handle, find the size
- // of the current preference, and increment it by the amount
- // of data we added. Note that this might fail on a 68000
- // processor (because it can't handle memory accesses to words
- // off word boundaries) but this isn't an issue because OT
- // requires an 68030 or above.
-
- if (err == noErr) {
- *((ByteCount *)((*(state->prefData)) + state->offsetToMostRecentPrefSize)) += size;
- }
-
- // Handle errors.
-
- if (err != noErr) {
- BuilderError(state, err);
- }
- }
- }
-
- static void BuilderNewPref(PrefBuilderState *state, OSType prefType, const void *data, ByteCount size)
- // Add a new preference to the builder, with the data specified
- // by data and size. You can pass nil and 0 to these parameters
- // to add an empty preference. Regardless, you can later call
- // BuilderAddPrefData to add extra data to this preference, up
- // until you call BuilderNewPref again.
- {
- OSStatus err;
- ByteCount initialPrefSize;
-
- if (state->prefData != nil) {
-
- // Add the preference type to the preference handle.
-
- err = PtrAndHand(&prefType, state->prefData, sizeof(prefType));
-
- // Record the current offset into the preference handle
- // (which is the offset of this preference size value,
- // which is needed by BuilderAddPrefData) and then add
- // a default size value of 0 to the preference.
-
- if (err == noErr) {
- state->offsetToMostRecentPrefSize = GetHandleSize(state->prefData);
- initialPrefSize = 0;
- err = PtrAndHand(&initialPrefSize, state->prefData, sizeof(initialPrefSize));
- }
-
- // Handle errors.
-
- if (err != noErr) {
- BuilderError(state, err);
- }
- }
-
- // Finally, call BuilderAddPrefData to add the actual
- // preference data. Note that if the above errored, the
- // error will have been latched in the state record, and
- // this call will be a no-op.
-
- if (size != 0) {
- BuilderAddPrefData(state, data, size);
- }
- }
-
- static OSStatus BuilderDone(PrefBuilderState *state, Handle *prefData)
- // Extracts the prefData from the builder state. You must
- // pass in a pointer to a nil handle. If building was successful,
- // this routine returns noErr and sets the handle to be
- // the built packed preferences. From there on, the memory
- // belongs to you.
- //
- // If the building was unsuccessful, the routine returns an error
- // and the handle remains nil.
-
- {
- OSStatus err;
-
- MoreAssertQ(prefData != nil);
-
- // Add a sentinel null OSType to the data handle.
-
- BuilderNewPref(state, 0, nil, 0);
-
- // Return the latched error code.
-
- if (state->prefData == nil) {
- err = state->latchedError;
- } else {
- err = noErr;
- }
- *prefData = state->prefData;
-
- MoreAssertQ( err == noErr && *prefData != nil || err != noErr && *prefData == nil );
-
- return err;
- }
-
- static void WriterGetNextPref(ByteCount *cookie, Ptr prefData, OSType *prefType, void **prefPtr, ByteCount *prefSize)
- // This routine provides a simple way for you to iterate over
- // a group of packed preferences. You get the first preference
- // by setting *cookie to 0 and calling the routine. The routine
- // returns the preference, and updates *cookie so that next time
- // you call it you get the second preference, and so on.
- //
- // prefData must point to a packed preference structure, as described
- // in the comments at the start of this section. Typically you get
- // this by locking and dereferencing the handle returned by BuilderDone.
- // [Locking the handle is advised by not strictly necessary as
- // long as you take care not to move or purge between when this routine
- // returns and when you use *prefPtr.] You don't have to pass in
- // the size of this handle because it's terminated by a null preference
- // type. You can keep calling this routine until *prefType is returned
- // as 0, in which case you've hit the end of the packed preferences.
- //
- // The routine sets *prefType to the type of the preference, and
- // *prefPtr and *prefSize to point to the preference data itself.
- // Note that *prefPtr is not necessarily aligned to any memory
- // boundary, so if you access it as a word or long pointer on an
- // original 68000 you may cause an address error.
- {
- MoreAssertQ(cookie != nil);
- MoreAssertQ(prefData != nil);
- MoreAssertQ(prefType != nil);
- MoreAssertQ(prefSize != nil);
- MoreAssertQ(prefPtr != nil);
-
- *prefType = *((OSType *)(prefData + *cookie));
- *cookie += sizeof(OSType); // skip cookie past the prefType
- *prefSize = *((ByteCount *)(prefData + *cookie));
- *cookie += sizeof(ByteCount); // skip cookie past the prefSize
- *prefPtr = prefData + *cookie;
- *cookie += *prefSize; // skip cookie past the data
- }
-
- static Handle NSHGetDefaultPreference(ResType entityType, ResType entityClass, ResType recordType)
- // Returns a handle containing a default value for the preference
- // of the given entity, class and preference type, or nil if there
- // is not such value (or there isn't enough memory to get it).
- // The result is a memory handle, for which you are responsible for
- // disposing.
- //
- // I decided not to export this routine because of its limited value
- // to external clients. But it follows the standard outline used
- // by external routines.
- {
- Handle result;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- result = OTCfgGetDefault(entityType, entityClass, recordType);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return nil;
- #endif
- } else {
- if ( entityType == kOTCfgTypeRemote && entityClass == kOTCfgClassNetworkConnection && recordType == kOTCfgRemoteLCPPref) {
- if ( PtrToHand(gRemoteLCPValue, &result, sizeof(gRemoteLCPValue)) != noErr ) {
- result = nil;
- }
- } else {
- result = nil;
- }
- }
- return result;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- TCP/IP Packer/Unpacker ------
-
- // These routines convert between the TCP/IP configuration digest
- // (a big record with all the relevant fields in it) and the
- // packed preferences data (which is read from or written to the
- // preferences store). These routines are shared between the
- // preferences database and preferences file implementations.
-
- static const char *gProtocolName = "tcp";
-
- static OSStatus BuildPackedPrefsFromTCPv4ConfigurationDigest(
- const NSHTCPv4ConfigurationDigest *configurationDigest,
- Boolean forceDefaults,
- Handle *packedPrefs)
- // This routine converts a TCP/IP configuration digest
- // to a handle containing packed preferences. The forceDefaults
- // parameter controls what happens to handle-based fields,
- // ie Handle fields in the digest. Normally, if such a field
- // is nil, it's taken to mean "don't change". However, if
- // forceDefaults is true, a nil means "write default value".
- // This happens when we're creating a new configuration,
- // where we want to make sure that empty default preferences
- // are created for these handle-based fields.
- {
- OSStatus err;
- OTPortRecord portRec;
- Str255 portUserVisibleName;
- Boolean isMacIP;
- Str63 portName;
- Str63 moduleName;
- UInt8 tmpUInt8;
- UInt16 tmpUInt16;
- const char *kMacIPUserVisibleName = "AppleTalk (Mac IP)";
- static UInt8 zeros[25] = {0};
- PrefBuilderState state;
- SInt8 s;
-
- MoreAssertQ(configurationDigest != nil);
- MoreAssertQ(packedPrefs != nil);
-
- *packedPrefs = nil;
-
- err = noErr;
- if ( OTFindPortByRef(&portRec, configurationDigest->fPortRef) ) {
- portName[0] = OTStrLength(portRec.fPortName);
- BlockMoveData(portRec.fPortName, &portName[1], portName[0]);
- moduleName[0] = OTStrLength(portRec.fModuleName);
- BlockMoveData(portRec.fModuleName, &moduleName[1], moduleName[0]);
- } else {
- err = kOTNotFoundErr;
- }
-
- if (err == noErr) {
- BuilderNew(&state);
-
- // 'pnam'
-
- BuilderNewPref(&state, kOTCfgUserVisibleNamePref, configurationDigest->fConfigName, configurationDigest->fConfigName[0] + 1);
-
- // 'port'
-
- isMacIP = OTStrEqual(portRec.fModuleName, "ddp");
- if (isMacIP) {
- portUserVisibleName[0] = OTStrLength(kMacIPUserVisibleName);
- BlockMoveData(kMacIPUserVisibleName, &portUserVisibleName[1], portUserVisibleName[0]);
- } else {
- OTGetUserPortNameFromPortRef(configurationDigest->fPortRef, portUserVisibleName);
- }
- BuilderNewPref(&state, kOTCfgPortUserVisibleNamePref, portUserVisibleName, portUserVisibleName[0] + 1);
-
- // 'pwrd'
-
- tmpUInt8 = 0;
- BuilderNewPref(&state, kOTCfgAdminPasswordPref, &tmpUInt8, sizeof(tmpUInt8));
-
- // 'cvrs'
-
- tmpUInt16 = 1;
- BuilderNewPref(&state, kOTCfgVersionPref, &tmpUInt16, sizeof(tmpUInt16));
-
- // 'prot'
-
- BuilderNewPref(&state, kOTCfgProtocolUserVisibleNamePref, gProtocolName, OTStrLength(gProtocolName) + 1);
-
- // 'unld'
-
- BuilderNewPref(&state, kOTCfgTCPUnloadAttrPref, &configurationDigest->fUnloadAttr, sizeof(configurationDigest->fUnloadAttr));
-
- // 'idns'
-
- if (configurationDigest->fDNSServerList != nil) {
- UInt16 numServers;
-
- MoreAssertQ(GetHandleSize(configurationDigest->fDNSServerList) % sizeof(InetHost) == 0);
- numServers = GetHandleSize(configurationDigest->fDNSServerList) / sizeof(InetHost);
-
- BuilderNewPref(&state, kOTCfgTCPDNSServersListPref, &numServers, sizeof(numServers));
- s = HGetState(configurationDigest->fDNSServerList);
- HLock(configurationDigest->fDNSServerList);
- BuilderAddPrefData(&state, *configurationDigest->fDNSServerList, GetHandleSize(configurationDigest->fDNSServerList));
- HSetState(configurationDigest->fDNSServerList, s);
- } else if (forceDefaults) {
- tmpUInt16 = 0;
- BuilderNewPref(&state, kOTCfgTCPDNSServersListPref, &tmpUInt16, sizeof(tmpUInt16));
- }
-
- // 'ihst'
-
- tmpUInt8 = 1;
- BuilderNewPref(&state, kOTCfgTCPSearchListPref, &tmpUInt8, sizeof(tmpUInt8));
- BuilderAddPrefData(&state, configurationDigest->fLocalDomain, configurationDigest->fLocalDomain[0] + 1);
- BuilderAddPrefData(&state, configurationDigest->fAdminDomain, configurationDigest->fAdminDomain[0] + 1);
-
- // 'iitf'
-
- tmpUInt16 = 1;
- BuilderNewPref(&state, kOTCfgTCPInterfacesPref, &tmpUInt16, sizeof(tmpUInt16));
- BuilderAddPrefData(&state, &configurationDigest->fConfigMethod, sizeof(configurationDigest->fConfigMethod));
- BuilderAddPrefData(&state, &configurationDigest->fIPAddress, sizeof(configurationDigest->fIPAddress));
- BuilderAddPrefData(&state, &configurationDigest->fSubnetMask, sizeof(configurationDigest->fSubnetMask));
- if (isMacIP) {
- BuilderAddPrefData(&state, configurationDigest->fAppleTalkZone, configurationDigest->fAppleTalkZone[0] + 1);
- BuilderAddPrefData(&state, "\pddp", 36);
- } else {
- BuilderAddPrefData(&state, "\p*", 2);
- BuilderAddPrefData(&state, portName, 36);
- }
- BuilderAddPrefData(&state, moduleName, 32);
- BuilderAddPrefData(&state, &configurationDigest->fFraming, sizeof(configurationDigest->fFraming));
-
- // 'dtyp'
-
- if (isMacIP) {
- tmpUInt16 = kOTNoDeviceType;
- } else {
- tmpUInt16 = OTGetDeviceTypeFromPortRef(configurationDigest->fPortRef);
- }
- BuilderNewPref(&state, kOTCfgTCPDeviceTypePref, &tmpUInt16, sizeof(tmpUInt16));
-
- // 'stng'
-
- BuilderNewPref(&state, kOTCfgTCPLocksPref, zeros, sizeof(zeros));
-
- // 'isdm'
-
- if (configurationDigest->fSearchDomains != nil) {
- s = HGetState(configurationDigest->fSearchDomains);
- HLock(configurationDigest->fSearchDomains);
- BuilderNewPref(&state, kOTCfgTCPSearchDomainsPref, *configurationDigest->fSearchDomains, GetHandleSize(configurationDigest->fSearchDomains));
- HSetState(configurationDigest->fSearchDomains, s);
- } else if (forceDefaults) {
- tmpUInt16 = 0;
- BuilderNewPref(&state, kOTCfgTCPSearchDomainsPref, &tmpUInt16, sizeof(tmpUInt16));
- }
-
- // 'irte'
-
- if (configurationDigest->fRouterList != nil || forceDefaults) {
- UInt16 numRouters;
- UInt16 routerIndex;
-
- if (configurationDigest->fRouterList == nil) {
- numRouters = 0;
- } else {
- MoreAssertQ(GetHandleSize(configurationDigest->fRouterList) % sizeof(InetHost) == 0);
- numRouters = GetHandleSize(configurationDigest->fRouterList) / sizeof(InetHost);
- }
- BuilderNewPref(&state, kOTCfgTCPRoutersListPref, &numRouters, sizeof(numRouters));
- for (routerIndex = 0; routerIndex < numRouters; routerIndex++) {
- OTCfgTCPRoutersListEntry entry;
-
- entry.fToHost = 0;
- entry.fViaHost = (*((InetHost **) configurationDigest->fRouterList))[routerIndex];
- entry.fLocal = 0;
- entry.fHost = 0;
- BuilderAddPrefData(&state, &entry, sizeof(entry));
- }
- }
-
- err = BuilderDone(&state, packedPrefs);
- }
-
- return err;
- }
-
- static Boolean UnpackTCPSearchList(const UInt8 *data, ByteCount length, NSHTCPv4ConfigurationDigest *configurationDigest)
- // This routine is used to unpacked the TCP search list preference
- // (kOTCfgTCPSearchListPref == 'ihst'). The preference is a weird
- // combination of packed strings and straight data, so we have to
- // mess around a bit. The routine returns true if it could
- // parse the data successfully; false if it found a formatting
- // error in the data.
- {
- const UInt8 *cursor;
- UInt8 primaryInterfaceIndex;
- MoreAssertQ(data != nil);
- MoreAssertQ(configurationDigest != nil);
-
- cursor = data;
- if (cursor + sizeof(SInt8) <= data + length) {
- primaryInterfaceIndex = *cursor;
- cursor += sizeof(SInt8);
- }
- if (cursor + *cursor + 1 <= data + length) {
- BlockMoveData(cursor, configurationDigest->fLocalDomain, *cursor + 1);
- cursor += (*cursor + 1);
- }
- if (cursor + *cursor + 1 <= data + length) {
- BlockMoveData(cursor, configurationDigest->fAdminDomain, *cursor + 1);
- cursor += (*cursor + 1);
- }
- return (primaryInterfaceIndex == 1) && (cursor == data + length);
- }
-
- static void UnpackTCPPrefs(Ptr *buffer, NSHTCPv4ConfigurationDigest *configurationDigest)
- // This routine unpacks an interface from an 'iitf' (kOTCfgTCPInterfacesPref)
- // preference into the relevant fields of a NSHTCPv4ConfigurationDigest.
- // *buffer must point to the beginning
- // of the interface, ie two bytes into the pref data if
- // if you're extracting the first interface. *buffer
- // is updated to point to the byte after the last byte
- // parsed, so you can parse multiple interfaces by
- // repeatedly calling this routine. You can also
- // check *buffer to determine whether the routine
- // consumed all the data you expected, and hence whether
- // the preference is formatted correctly.
- {
- UInt8 *cursor;
-
- cursor = (UInt8 *) *buffer;
-
- configurationDigest->fConfigMethod = *cursor;
- cursor += sizeof(UInt8);
- configurationDigest->fIPAddress = *((InetHost *) cursor);
- cursor += sizeof(InetHost);
- configurationDigest->fSubnetMask = *((InetHost *) cursor);
- cursor += sizeof(InetHost);
-
- // fAppleTalkZone is a Str32. A longer string in the
- // 'iitf' is a bug in the person who wrote the code and
- // causes us to stop parsing. The caller will notice that
- // the cursor did not advance far enough and error out.
-
- if ( *cursor <= 32 ) {
- BlockMoveData(cursor, configurationDigest->fAppleTalkZone, *cursor + 1);
- cursor += (*cursor + 1);
- BlockMoveData(cursor, configurationDigest->fHintPortName, 36);
- cursor += 36;
- BlockMoveData(cursor, configurationDigest->fHintDriverName, 32);
- cursor += 32;
- configurationDigest->fFraming = *((UInt32 *) cursor);
- cursor += sizeof(UInt32);
- }
-
- *buffer = (Ptr) cursor;
- }
-
- static Boolean PortMatchesTCPv4Hints(const OTPortRecord *portRec, const NSHTCPv4ConfigurationDigest *hints)
- // This routine checks whether a particular port matches the set
- // of hints extracted from the TCP/IP preferences, and returns true
- // if it does. The hints include:
- //
- // a) the user-visible name of the port,
- // b) the port name itself,
- // c) the name of the module controlling the part, and
- // d) the device type of the module controlling the port.
- {
- Str255 userVisibleName;
-
- OTGetUserPortNameFromPortRef(portRec->fRef, userVisibleName);
- return OTMemcmp(userVisibleName, hints->fHintUserVisiblePortName, userVisibleName[0] + 1)
- && OTStrEqual(portRec->fPortName, ((char *) hints->fHintPortName) + 1)
- && OTStrEqual(portRec->fModuleName, ((char *) hints->fHintDriverName) + 1)
- && OTGetDeviceTypeFromPortRef(portRec->fRef) == hints->fHintDeviceType;
- }
-
- static void ClearTCPv4ConfigurationDigest(NSHTCPv4ConfigurationDigest *configurationDigest)
- // Clear out the entire parameter block, preserving the handle-based fields.
- {
- Handle saveRouterList;
- Handle saveDNSServerList;
- Handle saveSearchDomains;
-
- saveRouterList = configurationDigest->fRouterList;
- saveDNSServerList = configurationDigest->fDNSServerList;
- saveSearchDomains = configurationDigest->fSearchDomains;
- OTMemzero(configurationDigest, sizeof(configurationDigest));
- configurationDigest->fRouterList = saveRouterList;
- configurationDigest->fDNSServerList = saveDNSServerList;
- configurationDigest->fSearchDomains = saveSearchDomains;
- }
-
- static OSStatus BuildTCPv4ConfigurationDigestFromPackedPrefs(Handle packedPrefs,
- NSHTCPv4ConfigurationDigest *configurationDigest)
- // This routine fills out a TCP/IP configuration digest
- // based on the packed preferences. The basic algorithm
- // is to iterate through all the preferences, looking at
- // each one and putting the data from that preference into
- // the configuration digest. At the end it does some jiggery
- // pokery that's explained in the comment down there.
- {
- OSStatus err;
- SInt8 s;
- ByteCount cookie;
- OSType prefType;
- ByteCount prefSize;
- void *prefData;
- UInt16 numServers;
- UInt16 numRouters;
- UInt16 routerIndex;
- OTPortRecord portRec;
-
- MoreAssertQ(packedPrefs != nil);
- MoreAssertQ(configurationDigest != nil);
-
- ClearTCPv4ConfigurationDigest(configurationDigest);
-
- configurationDigest->fProtocol = kOTCfgTypeTCPv4;
-
- s = HGetState(packedPrefs);
- HLock(packedPrefs);
-
- err = noErr;
- cookie = 0;
- do {
- WriterGetNextPref(&cookie, *packedPrefs, &prefType, &prefData, &prefSize);
- switch (prefType) {
- case 0:
- // do nothing, this is the loop exit condition
- break;
-
- // 'pnam'
-
- case kOTCfgUserVisibleNamePref:
- if ( prefSize <= sizeof(Str255) && prefSize == ((UInt8 *)prefData)[0] + 1 ) {
- BlockMoveData(prefData, configurationDigest->fConfigName, sizeof(Str255));
- } else {
- err = -8;
- }
- break;
-
- // 'port'
-
- case kOTCfgPortUserVisibleNamePref:
- if ( prefSize <= sizeof(Str255) && prefSize == ((UInt8 *)prefData)[0] + 1 ) {
- BlockMoveData(prefData, configurationDigest->fHintUserVisiblePortName, sizeof(Str255));
- } else {
- err = -8;
- }
- break;
-
- // 'pwrd'
-
- case kOTCfgAdminPasswordPref:
- // do nothing, we can ignore password prefs
- break;
-
- // 'cvrs'
-
- case kOTCfgVersionPref:
- // do nothing, except check that it's what we expect
- if ( prefSize != sizeof(UInt16) || *((UInt16 *)prefData) != 1) {
- err = -8;
- }
- break;
-
- // 'prot'
-
- case kOTCfgProtocolUserVisibleNamePref:
- // do nothing, except check it's TCP/IP
- if ( prefSize != OTStrLength(prefData) + 1 || ! OTStrEqual(prefData, gProtocolName) ) {
- err = -8;
- }
- break;
-
- // 'unld'
-
- case kOTCfgTCPUnloadAttrPref:
- configurationDigest->fUnloadAttr = *((UInt16 *)prefData);
- if ( prefSize != sizeof(UInt16)
- || configurationDigest->fUnloadAttr < kOTCfgTCPActiveLoadedOnDemand
- || configurationDigest->fUnloadAttr > kOTCfgTCPInactive ) {
- err = -8;
- }
- break;
-
- // 'idns'
-
- case kOTCfgTCPDNSServersListPref:
- numServers = *((UInt16 *)prefData);
- if ( prefSize == sizeof(UInt16) + numServers * sizeof(InetHost) ) {
- if (configurationDigest->fDNSServerList != nil) {
- err = PtrToXHand( ((char *) prefData) + sizeof(UInt16), configurationDigest->fDNSServerList, prefSize - sizeof(UInt16));
- }
- } else {
- err = -8;
- }
- break;
-
- // 'ihst'
-
- case kOTCfgTCPSearchListPref:
- if ( ! UnpackTCPSearchList(prefData, prefSize, configurationDigest) ) {
- err = -8;
- }
- break;
-
- // 'iitf'
-
- case kOTCfgTCPInterfacesPref:
- if ( prefSize >= sizeof(UInt16) && *((UInt16 *)prefData) == 1 ) {
- Ptr cursor;
-
- cursor = (Ptr) prefData;
- cursor += sizeof(UInt16);
-
- UnpackTCPPrefs(&cursor, configurationDigest);
-
- if ( cursor != ((Ptr) prefData) + prefSize ) {
- err = -8;
- }
- } else {
- err = -8;
- }
- break;
-
- // 'dtyp'
-
- case kOTCfgTCPDeviceTypePref:
- if (prefSize == sizeof(SInt16)) {
- configurationDigest->fHintDeviceType = *((UInt16 *)prefData);
- } else {
- err = -8;
- }
- break;
-
- // 'stng'
-
- case kOTCfgTCPLocksPref:
- // The pref should be of size 25, but I've seen
- // cases where it was set to 27. I have no idea
- // what causes this, but seeing as the size (or
- // indeed the contents) doesn't matter for this
- // program, I decided to handle that case.
- if (prefSize != 25 && prefSize != 27) {
- err = -8;
- }
- break;
-
- // 'isdm'
-
- case kOTCfgTCPSearchDomainsPref:
- if (prefSize >= sizeof(UInt16)) {
- if ( configurationDigest->fSearchDomains != nil ) {
- err = PtrToXHand(prefData, configurationDigest->fSearchDomains, prefSize);
- if (err == noErr) {
- if ( ! ValidStringListHandle( configurationDigest->fSearchDomains ) ) {
- err = -8;
- }
- }
- }
- } else {
- err = -8;
- }
- break;
-
- // 'irte'
-
- case kOTCfgTCPRoutersListPref:
- numRouters = *((UInt16 *)prefData);
- if ( prefSize == sizeof(UInt16) + numRouters * sizeof(OTCfgTCPRoutersListEntry) ) {
- if (configurationDigest->fRouterList != nil) {
- SetHandleSize(configurationDigest->fRouterList, numRouters * sizeof(InetHost));
- err = MemError();
- if (err == noErr) {
- OTCfgTCPRoutersList *prefRouterList;
- InetHost *digestRouterList;
-
- prefRouterList = (OTCfgTCPRoutersList *) prefData;
- digestRouterList = (InetHost *) *configurationDigest->fRouterList;
- for (routerIndex = 0; routerIndex < numRouters; routerIndex++) {
- digestRouterList[routerIndex] = prefRouterList->fList[routerIndex].fViaHost;
- // Should really check that the other fields of
- // the OTCfgTCPRoutersListEntry are zero, but I can't be bothered
- // right now.
- }
- }
- }
- } else {
- err = -8;
- }
- break;
-
- case kOTCfgUserModePref: // user level
- case kOTCfgPrefWindowPositionPref: // control panel window position
- case kOTCfgTCPDHCPClientIDPref: // DHCP client ID
- case kOTCfgTCPDHCPLeaseInfoPref: // DHCP persistent state
- case kOTCfgTCPPushBelowIPPref: // below IP module
- case kOTCfgTCPPushBelowIPListPref: // below IP module list (OT 2.5 and higher)
- case kOTCfgProtocolOptionsPref: // wacky protocol options
- case 'vers': // occasionally you find these in TCP/IP configs, although they shouldn't be there
- // Known preferences which we don't need to pay
- // attention to but shouldn't cause the following
- // assert to trigger.
- break;
-
- default:
- // Unexpected preference type in the packed prefs.
- // This is not super-fatal, but let the developer know in debug builds.
- MoreAssertQ(false);
- break;
- }
- } while (err == noErr && prefType != 0);
-
- HSetState(packedPrefs, s);
-
- // Before we leave, we have to set up the fPortRef field of the
- // configuration digest. This is a tricky business because the
- // port that we last used might have been removed, or ejected,
- // and replaced by another remarkably similar port. So we
- // only set up fPortRef is *all* of the hints we extracted from
- // the preferences match the port we found. Otherwise, we
- // leave fPortRef set to 0 and expect the client to do the
- // matching based on the hints.
- //
- // Except, of course, for MacIP, where the algorithm is completely
- // different, as always.
-
- if (err == noErr) {
- // Put a null byte after the last byte of these two hints.
- // We know we have the space because they're declared as
- // Str63s. We need this for later string comparisons,
- // both here and in PortMatchesTCPv4Hints.
-
- configurationDigest->fHintPortName[configurationDigest->fHintPortName[0] + 1] = 0;
- configurationDigest->fHintDriverName[configurationDigest->fHintDriverName[0] + 1] = 0;
-
- // Translation of the below:
- //
- // if the driver name was "ddp" and AppleTalk is active,
- // return the port ref of the active AppleTalk port
- // else if we have a port which exactly matches all the hints,
- // return the port ref of that port
- // else
- // return 0
- // end-if
-
- if ( ( OTStrEqual(((char *) configurationDigest->fHintDriverName) + 1, "ddp")
- && OTFindPort(&portRec, "ddp1") )
- || ( OTFindPort(&portRec, ((char *) configurationDigest->fHintPortName) + 1)
- && PortMatchesTCPv4Hints(&portRec, configurationDigest) ) ) {
- configurationDigest->fPortRef = portRec.fRef;
- } else {
- configurationDigest->fPortRef = kOTInvalidPortRef;
- }
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Remote Access Packer/Unpacker ------
-
- // These routines convert between the Remote Access configuration digest
- // (a big record with all the relevant fields in it) and the
- // packed preferences data (which is read from or written to the
- // preferences store). These routines are shared between the
- // preferences database and preferences file implementations.
-
- static Boolean RemoteVersionAcceptable(UInt32 version)
- // This routine returns true if the version number passed
- // in indicates that the preference was written by a
- // version of Remote Access whose preferences we understand.
- {
- return version == kOTCfgRemoteDefaultVersion || version == kOTCfgRemoteAcceptedVersion;
- }
-
- static OSStatus BuildPackedPrefsFromRemoteConfigurationDigest(
- const NSHRemoteConfigurationDigest *configurationDigest,
- Boolean forceDefaults,
- Handle *packedPrefs)
- // This routine converts a Remote Access configuration digest
- // to a handle containing packed preferences.
- //
- // forceDefaults is not needed for Remote Access because the
- // only handle-based field is an optional preference.
- {
- #pragma unused(forceDefaults)
- OSStatus err;
- PrefBuilderState state;
- UInt8 buffer[600];
- UInt32 tmpUInt32;
- Str255 encodedPassword;
- Handle prefH;
-
- MoreAssertQ(configurationDigest != nil);
- MoreAssertQ(packedPrefs != nil);
-
- *packedPrefs = nil;
-
- err = noErr;
-
- if (err == noErr) {
- BuilderNew(&state);
-
- // 'pnam'
-
- BuilderNewPref(&state, kOTCfgUserVisibleNamePref, configurationDigest->fConfigName, configurationDigest->fConfigName[0] + 1);
-
- // 'conn'
-
- {
- OTCfgRemoteConnect *connectPtr;
-
- OTMemzero(buffer, sizeof(buffer));
- MoreAssertQ(sizeof(buffer) >= sizeof(OTCfgRemoteConnect));
- connectPtr = (OTCfgRemoteConnect *) buffer;
-
- connectPtr->version = kOTCfgRemoteDefaultVersion;
- connectPtr->isGuest = configurationDigest->fGuestLogin;
- connectPtr->canInteract = true;
- connectPtr->passwordSaved = configurationDigest->fPasswordValid;
- connectPtr->flashConnectedIcon = configurationDigest->fFlashIconWhileConnected;
- connectPtr->issueConnectedReminders = configurationDigest->fPromptToRemainConnected;
- connectPtr->reminderMinutes = configurationDigest->fPromptInterval;
- connectPtr->allowModemDataCompression = configurationDigest->fPPPAllowModemCompression;
- connectPtr->chatMode = configurationDigest->fPPPConnectMode;
- connectPtr->serialProtocolMode = configurationDigest->fSerialProtocol;
-
- connectPtr->addressLength = configurationDigest->fPhoneNumber[0];
- BlockMoveData(configurationDigest->fPPPConnectScriptName, connectPtr->chatScriptName, sizeof(Str63));
- if ( configurationDigest->fPPPConnectScript != nil ) {
- connectPtr->chatScriptLength = GetHandleSize(configurationDigest->fPPPConnectScript);
- }
- BuilderNewPref(&state, kOTCfgRemoteConnectPref, connectPtr, sizeof(*connectPtr));
- }
-
- // 'cusr'
-
- BuilderNewPref(&state, kOTCfgRemoteUserPref, configurationDigest->fUserName, configurationDigest->fUserName[0] + 1);
-
- // 'pass'
-
- err = NSHEncodeRemotePassword(configurationDigest->fUserName, configurationDigest->fPassword, encodedPassword);
- if (err == noErr) {
- BuilderNewPref(&state, kOTCfgRemotePasswordPref, encodedPassword, sizeof(Str255));
- } else {
- BuilderError(&state, err);
- }
-
- // 'cadr'
-
- BuilderNewPref(&state, kOTCfgRemoteAddressPref, &configurationDigest->fPhoneNumber[1], configurationDigest->fPhoneNumber[0]);
-
- // 'cdia'
-
- {
- OTCfgRemoteDialing *dialPtr;
-
- OTMemzero(buffer, sizeof(buffer));
- MoreAssertQ(sizeof(buffer) >= sizeof(OTCfgRemoteDialing));
- dialPtr = (OTCfgRemoteDialing *) buffer;
-
- dialPtr->version = kOTCfgRemoteDefaultVersion;
- dialPtr->fType = 'dial';
- dialPtr->dialMode = configurationDigest->fRedialMode;
- dialPtr->redialTries = configurationDigest->fRedialTimes;
- dialPtr->redialDelay = configurationDigest->fRedialDelay;
-
- BuilderNewPref(&state, kOTCfgRemoteDialingPref, dialPtr, sizeof(*dialPtr));
- }
-
- // 'cead'
-
- if ( configurationDigest->fRedialMode == kOTCfgRemoteRedialMainAndAlternate ) {
- tmpUInt32 = 0;
- BuilderNewPref(&state, kOTCfgRemoteAlternateAddressPref, &tmpUInt32, sizeof(tmpUInt32));
- BuilderAddPrefData(&state, configurationDigest->fAlternatePhoneNumber, sizeof(Str255));
- }
-
- // 'logo'
-
- {
- OTCfgRemoteLogOptions *logPtr;
-
- OTMemzero(buffer, sizeof(buffer));
- MoreAssertQ(sizeof(buffer) >= sizeof(OTCfgRemoteLogOptions));
- logPtr = (OTCfgRemoteLogOptions *) buffer;
-
- logPtr->version = kOTCfgRemoteDefaultVersion;
- logPtr->fType = 'lgop';
- logPtr->logLevel = configurationDigest->fVerboseLogging;
-
- BuilderNewPref(&state, kOTCfgRemoteLogOptionsPref, logPtr, sizeof(*logPtr));
- }
-
- // 'ipcp'
-
- {
- OTCfgRemoteIPCP *ipcpPtr;
-
- OTMemzero(buffer, sizeof(buffer));
- MoreAssertQ(sizeof(buffer) >= sizeof(OTCfgRemoteIPCP));
- ipcpPtr = (OTCfgRemoteIPCP *) buffer;
-
- ipcpPtr->version = kOTCfgRemoteDefaultVersion;
- ipcpPtr->reserved[0] = 'ipcp';
- ipcpPtr->maxConfig = 10;
- ipcpPtr->maxTerminate = 10;
- ipcpPtr->maxFailureLocal = 10;
- ipcpPtr->maxFailureRemote = 10;
- ipcpPtr->timerPeriod = 10000;
- ipcpPtr->localIPAddress = 0;
- ipcpPtr->remoteIPAddress = 0;
- ipcpPtr->allowAddressNegotiation = 1;
- ipcpPtr->idleTimerEnabled = configurationDigest->fDisconnectIfIdle;
- ipcpPtr->compressTCPHeaders = configurationDigest->fPPPAllowTCPIPHeaderCompression;
- ipcpPtr->idleTimerMilliseconds = configurationDigest->fDisconnectInterval;
-
- BuilderNewPref(&state, kOTCfgRemoteIPCPPref, ipcpPtr, sizeof(*ipcpPtr));
- }
-
- // 'cmsc'
-
- tmpUInt32 = kOTCfgRemoteDefaultVersion;
- BuilderNewPref(&state, kOTCfgRemoteClientMiscPref, &tmpUInt32, sizeof(tmpUInt32));
- tmpUInt32 = configurationDigest->fPPPConnectAutomatically;
- BuilderAddPrefData(&state, &tmpUInt32, sizeof(tmpUInt32));
-
- // 'ccha'
-
- if ( configurationDigest->fPPPConnectScript != nil ) {
- SInt8 s;
-
- s = HGetState(configurationDigest->fPPPConnectScript);
- HLock(configurationDigest->fPPPConnectScript);
-
- BuilderNewPref(&state, kOTCfgRemoteChatPref, *configurationDigest->fPPPConnectScript, GetHandleSize(configurationDigest->fPPPConnectScript));
-
- HSetState(configurationDigest->fPPPConnectScript, s);
- }
-
- // 'lcp '
-
- prefH = NSHGetDefaultPreference(kOTCfgTypeRemote, kOTCfgClassNetworkConnection, kOTCfgRemoteLCPPref);
- if (prefH != nil) {
- MoreAssertQ(GetHandleSize(prefH) == sizeof(gRemoteLCPValue));
- HLock(prefH);
- MoreAssertQ(MemError() == noErr);
- BuilderNewPref(&state, kOTCfgRemoteLCPPref, *prefH, GetHandleSize(prefH));
- DisposeHandle(prefH);
- MoreAssertQ(MemError() == noErr);
- } else {
- BuilderError(&state, resNotFound);
- }
-
- // 'arap'
-
- tmpUInt32 = kOTCfgRemoteDefaultVersion;
- BuilderNewPref(&state, kOTCfgRemoteARAPPref, &tmpUInt32, sizeof(tmpUInt32));
- OTMemzero(buffer, sizeof(buffer));
- OTStrCopy( (char *) buffer, "Script");
- BuilderAddPrefData(&state, buffer, 36);
-
- // 'x25 '
- {
- OTCfgRemoteX25 *x25Ptr;
-
- OTMemzero(buffer, sizeof(buffer));
- MoreAssertQ(sizeof(buffer) >= sizeof(OTCfgRemoteX25));
- x25Ptr = (OTCfgRemoteX25 *) buffer;
-
- x25Ptr->version = kOTCfgRemoteDefaultVersion;
-
- BuilderNewPref(&state, kOTCfgRemoteX25Pref, x25Ptr, sizeof(*x25Ptr));
- }
-
- // 'dass'
-
- tmpUInt32 = kOTCfgRemoteDefaultVersion;
- BuilderNewPref(&state, kOTCfgRemoteDialAssistPref, &tmpUInt32, sizeof(tmpUInt32));
- OTMemzero(buffer, sizeof(buffer));
- BuilderAddPrefData(&state, buffer, 68);
-
- // 'usmd'
-
- tmpUInt32 = kOTCfgRemoteDefaultVersion;
- BuilderNewPref(&state, kOTCfgRemoteUserModePref, &tmpUInt32, sizeof(tmpUInt32));
- tmpUInt32 = 0x00000001;
- BuilderAddPrefData(&state, &tmpUInt32, sizeof(tmpUInt32));
- OTMemzero(buffer, sizeof(buffer));
- BuilderAddPrefData(&state, buffer, 256);
-
- // 'clks'
-
- tmpUInt32 = kOTCfgRemoteDefaultVersion;
- BuilderNewPref(&state, kOTCfgRemoteClientLocksPref, &tmpUInt32, sizeof(tmpUInt32));
- OTMemzero(buffer, sizeof(buffer));
- BuilderAddPrefData(&state, buffer, 64);
-
- err = BuilderDone(&state, packedPrefs);
- }
-
- return err;
- }
-
- static void ClearRemoteConfigurationDigest(NSHRemoteConfigurationDigest *configurationDigest)
- // Clear out the entire parameter block, preserving the handle-based fields.
- {
- Handle savePPPConnectScript;
-
- savePPPConnectScript = configurationDigest->fPPPConnectScript;
- OTMemzero(configurationDigest, sizeof(configurationDigest));
- configurationDigest->fPPPConnectScript = savePPPConnectScript;
- }
-
- static OSStatus BuildRemoteConfigurationDigestFromPackedPrefs(Handle packedPrefs,
- NSHRemoteConfigurationDigest *configurationDigest)
- // This routine fills out a Remote Access configuration digest
- // based on the packed preferences. The basic algorithm
- // is to iterate through all the preferences, looking at
- // each one and putting the data from that preference into
- // the configuration digest.
- {
- OSStatus err;
- SInt8 s;
- ByteCount cookie;
- OSType prefType;
- ByteCount prefSize;
- void *prefData;
-
- MoreAssertQ(packedPrefs != nil);
- MoreAssertQ(configurationDigest != nil);
-
- ClearRemoteConfigurationDigest(configurationDigest);
-
- configurationDigest->fProtocol = kOTCfgTypeRemote;
-
- s = HGetState(packedPrefs);
- HLock(packedPrefs);
-
- err = noErr;
- cookie = 0;
- do {
- WriterGetNextPref(&cookie, *packedPrefs, &prefType, &prefData, &prefSize);
- switch (prefType) {
- case 0:
- // do nothing, this is the loop exit condition
- break;
-
- // 'pnam'
-
- case kOTCfgUserVisibleNamePref:
- if ( prefSize <= sizeof(Str255) && prefSize == ((UInt8 *)prefData)[0] + 1 ) {
- BlockMoveData(prefData, configurationDigest->fConfigName, sizeof(Str255));
- } else {
- err = -8;
- }
- break;
-
- // 'cmsc' -> fPPPConnectAutomatically
-
- case kOTCfgRemoteClientMiscPref:
- if ( prefSize == 8 && RemoteVersionAcceptable(((UInt32 *) prefData)[0]) ) {
- configurationDigest->fPPPConnectAutomatically = ((UInt32 *) prefData)[1];
- } else {
- err = -8;
- }
- break;
-
- // 'conn' -> fGuestLogin, fPasswordValid, fPhoneNumber, fFlashIconWhileConnected, fPromptToRemainConnected, fPromptInterval, fSerialProtocol, fPPPAllowModemCompression, fPPPConnectMode, fPPPConnectScriptName, fPPPConnectScript
- case kOTCfgRemoteConnectPref:
- if ( prefSize == sizeof(OTCfgRemoteConnect) && RemoteVersionAcceptable(((UInt32 *) prefData)[0]) ) {
- OTCfgRemoteConnect *configPtr;
-
- configPtr = (OTCfgRemoteConnect *) prefData;
-
- configurationDigest->fGuestLogin = configPtr->isGuest;
- configurationDigest->fPasswordValid = configPtr->passwordSaved;
- configurationDigest->fFlashIconWhileConnected = configPtr->flashConnectedIcon;
- configurationDigest->fPromptToRemainConnected = configPtr->issueConnectedReminders;
- configurationDigest->fPromptInterval = configPtr->reminderMinutes;
- configurationDigest->fSerialProtocol = configPtr->serialProtocolMode;
- configurationDigest->fPPPAllowModemCompression = configPtr->allowModemDataCompression;
- configurationDigest->fPPPConnectMode = configPtr->chatMode;
- BlockMoveData(configPtr->chatScriptName, configurationDigest->fPPPConnectScriptName, sizeof(Str63));
- } else {
- err = -8;
- }
- break;
-
- // 'cusr' -> fUserName
-
- case kOTCfgRemoteUserPref:
- if ( prefSize <= sizeof(Str255) && prefSize == ((UInt8 *)prefData)[0] + 1 ) {
- BlockMoveData(prefData, configurationDigest->fUserName, sizeof(Str255));
- } else {
- err = -8;
- }
- break;
-
- // 'pass' -> fPassword
-
- case kOTCfgRemotePasswordPref:
- if ( prefSize == sizeof(Str255) ) {
- BlockMoveData(prefData, configurationDigest->fPassword, sizeof(Str255));
-
- // I deliberately didn't decode the password here. If you want
- // the decoded password, you have to do it yourself.
-
- } else {
- err = -8;
- }
- break;
-
- // 'cdia' -> fRedialMode, fRedialTimes, fRedialDelay
-
- case kOTCfgRemoteDialingPref:
- if ( prefSize == sizeof(OTCfgRemoteDialing)
- && RemoteVersionAcceptable(((UInt32 *)prefData)[0])
- && ((UInt32 *)prefData)[1] == 'dial') {
- OTCfgRemoteDialing *dialingPtr;
-
- dialingPtr = (OTCfgRemoteDialing *) prefData;
- configurationDigest->fRedialMode = dialingPtr->dialMode;
- configurationDigest->fRedialTimes = dialingPtr->redialTries;
- configurationDigest->fRedialDelay = dialingPtr->redialDelay;
- } else {
- err = -8;
- }
- break;
-
- // 'ipcp' -> fDisconnectIfIdle, fDisconnectInterval, fPPPAllowTCPIPHeaderCompression
-
- case kOTCfgRemoteIPCPPref:
- // Sometimes the second long of prefData has 'ipcp' in it, but
- // we can't check that because often it doesn't!
- if ( prefSize == sizeof(OTCfgRemoteIPCP) && RemoteVersionAcceptable(((UInt32 *)prefData)[0])) {
- OTCfgRemoteIPCP *ipcpPtr;
-
- ipcpPtr = (OTCfgRemoteIPCP *) prefData;
- configurationDigest->fDisconnectIfIdle = ipcpPtr->idleTimerEnabled;
- configurationDigest->fDisconnectInterval = ipcpPtr->idleTimerMilliseconds;
- configurationDigest->fPPPAllowTCPIPHeaderCompression = ipcpPtr->compressTCPHeaders;
- } else {
- err = -8;
- }
- break;
-
- // 'logo' -> fVerboseLogging
-
- case kOTCfgRemoteLogOptionsPref:
- if ( prefSize == sizeof(OTCfgRemoteLogOptions)
- && RemoteVersionAcceptable(((UInt32 *)prefData)[0])
- && ((UInt32 *)prefData)[1] == 'lgop') {
- OTCfgRemoteLogOptions *logPtr;
-
- logPtr = (OTCfgRemoteLogOptions *) prefData;
- configurationDigest->fVerboseLogging = logPtr->logLevel;
- } else {
- err = -8;
- }
- break;
-
- // 'cadr' -> fPhoneNumber
-
- case kOTCfgRemoteAddressPref:
- if ( prefSize <= 255 ) {
- configurationDigest->fPhoneNumber[0] = prefSize;
- BlockMoveData(prefData, &configurationDigest->fPhoneNumber[1], prefSize);
- } else {
- err = -8;
- }
- break;
-
- // 'cead' -> fAlternatePhoneNumber
-
- case kOTCfgRemoteAlternateAddressPref:
- if ( prefSize == sizeof(Str255) + sizeof(UInt32)
- && ((UInt32 *)prefData)[0] == 0) {
- BlockMoveData( ((char *)prefData) + sizeof(UInt32), configurationDigest->fAlternatePhoneNumber, sizeof(Str255));
- } else {
- err = -8;
- }
- break;
-
- // 'ccha' -> fPPPConnectScript
-
- case kOTCfgRemoteChatPref:
- if ( configurationDigest->fPPPConnectScript != nil ) {
- err = PtrToXHand(prefData, configurationDigest->fPPPConnectScript, prefSize);
- }
- break;
-
- case kOTCfgRemoteUserModePref:
- case kOTCfgRemoteClientLocksPref:
- case kOTCfgRemoteLCPPref:
- case kOTCfgRemoteARAPPref:
- case kOTCfgRemoteDialAssistPref:
- case kOTCfgRemoteX25Pref:
- case kOTCfgRemoteTerminalPref:
- // Known preferences which we don't need to pay
- // attention to but shouldn't cause the following
- // assert to trigger.
- break;
-
- default:
- // Unexpected preference type in the packed prefs.
- // This is not super-fatal, but let the developer know in debug builds.
- MoreAssertQ(false);
- break;
- }
- } while (err == noErr && prefType != 0);
-
- HSetState(packedPrefs, s);
-
- // Fix up the redial preferences. We should only return
- // an alternate redial phone number if the redial mode is
- // appropriate. This is not strictly necessary, but it
- // tidies up one of the anomalies noticed by the test case.
-
- if (err == noErr) {
- if ( configurationDigest->fRedialMode != kOTCfgRemoteRedialMainAndAlternate ) {
- configurationDigest->fAlternatePhoneNumber[0] = 0;
- }
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Modem Packer/Unpacker ------
-
- // These routines convert between the Modem configuration digest
- // (a big record with all the relevant fields in it) and the
- // packed preferences data (which is read from or written to the
- // preferences store). These routines are shared between the
- // preferences database and preferences file implementations.
-
- static OSStatus BuildPackedPrefsFromModemConfigurationDigest(
- const NSHModemConfigurationDigest *configurationDigest,
- Boolean forceDefaults,
- Handle *packedPrefs)
- // This routine converts a Modem configuration digest
- // to a handle containing packed preferences.
- //
- // forceDefaults is not needed because the Modem digest
- // has no handle-based field.
- {
- #pragma unused(forceDefaults)
- OSStatus err;
- OTPortRecord portRec;
- PrefBuilderState state;
- UInt8 buffer[256];
- OTCfgModemLocks *locksPtr;
- OTCfgModemGeneral *modemConfig;
-
- MoreAssertQ(configurationDigest != nil);
- MoreAssertQ(packedPrefs != nil);
-
- *packedPrefs = nil;
-
- err = noErr;
- if ( ! OTFindPortByRef(&portRec, configurationDigest->fPortRef) ) {
- err = kOTNotFoundErr;
- }
-
- if (err == noErr) {
- BuilderNew(&state);
-
- // 'pnam'
-
- BuilderNewPref(&state, kOTCfgUserVisibleNamePref, configurationDigest->fConfigName, configurationDigest->fConfigName[0] + 1);
-
- // 'ccl ' -> fPortRef, fModemScript, fDialToneMode, fSpeakerOn, fPulseDial, fHintPortName
-
- OTMemzero(buffer, sizeof(buffer));
- MoreAssertQ(sizeof(*modemConfig) <= sizeof(buffer));
- modemConfig = (OTCfgModemGeneral *) buffer;
- modemConfig->version = 0x00010000;
- modemConfig->useModemScript = true;
- modemConfig->modemScript = configurationDigest->fModemScript;
- modemConfig->modemSpeakerOn = configurationDigest->fSpeakerOn;
- modemConfig->modemPulseDial = configurationDigest->fPulseDial;
- modemConfig->modemDialToneMode = configurationDigest->fDialToneMode;
- BlockMoveData(portRec.fPortName, modemConfig->lowerLayerName, 36);
- BuilderNewPref(&state, kOTCfgModemGeneralPrefs, modemConfig, sizeof(*modemConfig));
-
- // 'lkmd' -> $00000001 + $00000000 * 4
-
- OTMemzero(buffer, sizeof(buffer));
- MoreAssertQ(sizeof(*locksPtr) <= sizeof(buffer));
- locksPtr = (OTCfgModemLocks *) buffer;
- locksPtr->version = 1;
- BuilderNewPref(&state, kOTCfgModemLocksPref, locksPtr, sizeof(*locksPtr));
-
- // 'mdpw' -> $00 * 256
-
- OTMemzero(buffer, sizeof(buffer));
- BuilderNewPref(&state, kOTCfgModemAdminPasswordPref, buffer, 256);
-
- err = BuilderDone(&state, packedPrefs);
- }
-
- return err;
- }
-
- static OSStatus BuildModemConfigurationDigestFromPackedPrefs(Handle packedPrefs,
- NSHModemConfigurationDigest *configurationDigest)
- // This routine fills out a Modem configuration digest
- // based on the packed preferences. The basic algorithm
- // is to iterate through all the preferences, looking at
- // each one and putting the data from that preference into
- // the configuration digest. At the end it does some jiggery
- // pokery that's explained in the comment down there.
- {
- OSStatus err;
- SInt8 s;
- ByteCount cookie;
- OSType prefType;
- ByteCount prefSize;
- void *prefData;
- OTPortRecord portRec;
- OTCfgModemGeneral *modemConfig;
-
- MoreAssertQ(packedPrefs != nil);
- MoreAssertQ(configurationDigest != nil);
-
- OTMemzero(configurationDigest, sizeof(configurationDigest));
-
- configurationDigest->fProtocol = kOTCfgTypeModem;
-
- s = HGetState(packedPrefs);
- HLock(packedPrefs);
-
- err = noErr;
- cookie = 0;
- do {
- WriterGetNextPref(&cookie, *packedPrefs, &prefType, &prefData, &prefSize);
- switch (prefType) {
- case 0:
- // do nothing, this is the loop exit condition
- break;
-
- // 'pnam'
-
- case kOTCfgUserVisibleNamePref:
- if ( prefSize <= sizeof(Str255) && prefSize == ((UInt8 *)prefData)[0] + 1 ) {
- BlockMoveData(prefData, configurationDigest->fConfigName, sizeof(Str255));
- } else {
- err = -8;
- }
- break;
-
- // 'ccl '
- case kOTCfgModemGeneralPrefs:
- modemConfig = (OTCfgModemGeneral *) prefData;
- if (prefSize == sizeof(OTCfgModemGeneral) && modemConfig->version == 0x00010000) {
- if (modemConfig->useModemScript) {
- configurationDigest->fModemScript = modemConfig->modemScript;
- } else {
- // leave fModemScript set to all zeros
- }
- configurationDigest->fSpeakerOn = modemConfig->modemSpeakerOn;
- configurationDigest->fPulseDial = modemConfig->modemPulseDial;
- configurationDigest->fDialToneMode = modemConfig->modemDialToneMode;
- configurationDigest->fHintPortName[0] = OTStrLength( (char *) modemConfig->lowerLayerName);
- MoreAssertQ(configurationDigest->fHintPortName[0] <= 63);
- BlockMoveData(modemConfig->lowerLayerName, &configurationDigest->fHintPortName[1], configurationDigest->fHintPortName[0]);
- } else {
- err = -8;
- }
-
- break;
-
- // 'lkmd'
-
- case kOTCfgModemLocksPref:
- // just check the size
- if (prefSize != 20) {
- err = -8;
- }
- break;
-
- // 'mdpw'
-
- case kOTCfgModemAdminPasswordPref:
- // just check the size
- if (prefSize != 256) {
- err = -8;
- }
- break;
-
- default:
- // Unexpected preference type in the packed prefs.
- // This is not super-fatal, but let the developer know in debug builds.
- MoreAssertQ(false);
- break;
- }
- } while (err == noErr && prefType != 0);
-
- HSetState(packedPrefs, s);
-
- // Before we leave, we have to set up the fPortRef field of the
- // configuration digest. This is much easier than it was for TCP/IP.
- // Basically, if we have a port that matches the port name stored
- // in the preferences, that's the one we're going to return.
-
- if (err == noErr) {
- // Put a null byte after the last byte of the hint.
- // We know we have the space because they're declared as
- // Str63s. We need this to pass it as a C string to OTFindPort.
-
- configurationDigest->fHintPortName[configurationDigest->fHintPortName[0] + 1] = 0;
-
- if ( OTFindPort(&portRec, ((char *) configurationDigest->fHintPortName) + 1) ) {
- configurationDigest->fPortRef = portRec.fRef;
- } else {
- configurationDigest->fPortRef = kOTInvalidPortRef;
- }
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Packer/Unpacker Dispatch ------
-
- static OSStatus BuildConfigurationDigestFromPackedPrefs(OSType protocol, Handle packedPrefs,
- NSHConfigurationDigest *configurationDigest)
- // A simple dispatcher that calls the appropriate protocol-specific
- // BuildXxxConfigurationDigestFromPackedPrefs routine based on the supplied
- // protocol.
- {
- OSStatus err;
-
- switch (protocol) {
- case kOTCfgTypeTCPv4:
- err = BuildTCPv4ConfigurationDigestFromPackedPrefs(packedPrefs, &configurationDigest->fTCPv4);
- break;
- case kOTCfgTypeRemote:
- err = BuildRemoteConfigurationDigestFromPackedPrefs(packedPrefs, &configurationDigest->fRemote);
- break;
- case kOTCfgTypeModem:
- err = BuildModemConfigurationDigestFromPackedPrefs(packedPrefs, &configurationDigest->fModem);
- break;
- default:
- err = paramErr;
- break;
- }
- return err;
- }
-
- static OSStatus BuildPackedPrefsFromConfigurationDigest(const NSHConfigurationDigest *configurationDigest, Boolean forceDefaults, Handle *packedPrefs)
- // A simple dispatcher that calls the appropriate protocol-specific
- // BuildPackedPrefsFromXxxConfigurationDigest routine based on the
- // protocol in the digest.
- {
- OSStatus err;
-
- switch (configurationDigest->fCommon.fProtocol) {
- case kOTCfgTypeTCPv4:
- err = BuildPackedPrefsFromTCPv4ConfigurationDigest(&configurationDigest->fTCPv4, forceDefaults, packedPrefs);
- break;
- case kOTCfgTypeRemote:
- err = BuildPackedPrefsFromRemoteConfigurationDigest(&configurationDigest->fRemote, forceDefaults, packedPrefs);
- break;
- case kOTCfgTypeModem:
- err = BuildPackedPrefsFromModemConfigurationDigest(&configurationDigest->fModem, forceDefaults, packedPrefs);
- break;
- default:
- err = paramErr;
- break;
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Internet Setup using Database ------
-
- static OSStatus WritePackedPrefsToDatabase(const MNSDatabaseRef *ref,
- const CfgEntityRef *configEntity,
- Handle packedPrefs)
- // This is a utility routine that simply writes the entire
- // set of packed preferences to the configuration database
- // entity specified by ref and configEntity.
- {
- SInt8 s;
- OSStatus err;
- ByteCount cookie;
- OSType prefType;
- ByteCount prefSize;
- void *prefPtr;
-
- MoreAssertQ(ref != nil);
- MoreAssertQ(configEntity != nil);
- MoreAssertQ(packedPrefs != nil);
-
- // Lock down the packed preferences.
-
- s = HGetState(packedPrefs);
- HLock(packedPrefs);
- MoreAssertQ(MemError() == noErr);
-
- // Iterate through each preference, write it out to the database.
-
- err = noErr;
- cookie = 0;
- do {
- WriterGetNextPref(&cookie, *packedPrefs, &prefType, &prefPtr, &prefSize);
- if (prefType != 0) {
- err = MNSSetPref(ref, configEntity, prefType, prefPtr, prefSize);
- }
- } while (err == noErr && prefType != 0);
-
- // Clean up.
-
- HSetState(packedPrefs, s);
-
- return err;
- }
-
- static pascal void BuilderIterator(OSType prefType, void *prefData, ByteCount prefSize, void *refcon)
- // This is an MNSIterateEntity callback routine. It simply
- // adds each preference in the entity to the the builder
- // whose state is passed in as the refcon parameter. The upshot
- // is that the entity's entire preference set is added to
- // the packed prefs. I love it when concepts like builders
- // and iterators work together (-:
- {
- switch (prefType) {
- case kOTCfgCompatResourceIDPref:
- case kOTCfgCompatResourceNamePref:
- case kOTCfgCompatNamePref:
- // Do nothing. These preferences are used purely by
- // Network Setup to maintain accurate roundtrip
- // conversions between the backward compatibility
- // files and the database. We never need the
- // information from the files, so we can just
- // ignore them completely.
- break;
- default:
- BuilderNewPref( (PrefBuilderState *) refcon, prefType, prefData, prefSize);
- break;
- }
- }
-
- static OSStatus ReadPackedPrefsFromDatabase(const MNSDatabaseRef *ref,
- const CfgEntityRef *configEntity,
- Handle *packedPrefs)
- // This routine builds a packed preference handle based on
- // all the preferences in the entity specified by ref and
- // configEntity. *packedPrefs must be nil before you call
- // the routine. The routine either succeeds (returning noErr
- // and setting *packedPrefs to a valid handle), or fails
- // (returning an error, and leaving *packedRefs as nil).
- {
- OSStatus err;
- OSStatus err2;
- PrefBuilderState state;
-
- MoreAssertQ(ref != nil);
- MoreAssertQ(configEntity != nil);
- MoreAssertQ(packedPrefs != nil);
- MoreAssertQ(*packedPrefs == nil);
-
- BuilderNew(&state);
- err = MNSIterateEntity(ref, configEntity, BuilderIterator, &state);
-
- err2 = BuilderDone(&state, packedPrefs);
- if (err == noErr) {
- err = err2;
- }
- MoreAssertQ(err != noErr && packedPrefs == nil || err == noErr && packedPrefs != nil);
- return err;
- }
-
- static void FillOutConfigBits(OSType protocol, ConstStr255Param name, NSHConfigurationEntry *thisConfig)
- // Fills out the name, selected and cookie3 fields of thisConfig.
- // This is basically common code extracted from CreateConfigurationDatabase
- // and DuplicateConfigurationDatabase.
- {
- MoreAssertQ(thisConfig != nil);
-
- BlockMoveData(name, thisConfig->name, sizeof(Str255));
- thisConfig->selected = false;
- thisConfig->cookie = 0;
- thisConfig->cookie3.fClass = kOTCfgClassNetworkConnection;
- thisConfig->cookie3.fType = protocol;
- BlockMoveData(name, thisConfig->cookie3.fName, sizeof(Str255));
- thisConfig->cookie3.fIcon.fFile.vRefNum = 0;
- thisConfig->cookie3.fIcon.fFile.parID = 0;
- thisConfig->cookie3.fIcon.fFile.name[0] = 0;
- thisConfig->cookie3.fIcon.fResID = 0;
- thisConfig->cookie4 = protocol;
- }
-
- static OSStatus CreateConfigurationDatabase(const NSHConfigurationDigest *configurationDigest,
- NSHConfigurationEntry *createdConfig)
- // Implementation of NSHCreateConfiguration which uses the Network Setup
- // database. See NSHCreateConfiguration's comment in header
- // file for interface specification.
- //
- // This routine opens up the database, creates an entity, and sets
- // the contents of the entity from the digest using common utility
- // routines. Plus there's a bunch of housekeeping that's documented
- // by comments in the routine.
- {
- OSStatus err;
- OSStatus err2;
- NSHConfigurationEntry tmpConfig;
- NSHConfigurationEntry *destConfig;
- MNSDatabaseRef ref;
- CfgAreaID originalArea;
- Handle packedPrefs;
-
- MoreAssertQ(configurationDigest != nil);
-
- // createdConfig is an optional parameter. To simplify our
- // code, we use a temporary config if the user didn't supply it.
-
- if (createdConfig != nil) {
- destConfig = createdConfig;
- } else {
- destConfig = &tmpConfig;
- }
-
- packedPrefs = nil;
-
- err = MNSOpenDatabase(&ref, true);
- if (err == noErr) {
- FillOutConfigBits(configurationDigest->fCommon.fProtocol, configurationDigest->fCommon.fConfigName, destConfig);
-
- // Create the entity, getting back the CfgEntityRef.
-
- err = OTCfgCreateEntity(ref.dbRef, ref.area, &destConfig->cookie3,
- &destConfig->cookie2);
- if (err == noErr) {
-
- // Fill out the entity with the information from the digest.
-
- err = BuildPackedPrefsFromConfigurationDigest(configurationDigest, true, &packedPrefs);
- if (err == noErr) {
- err = WritePackedPrefsToDatabase(&ref, &destConfig->cookie2, packedPrefs);
- }
-
- if (err != noErr) {
- // There is no need to delete the half-created config
- // because we're about to abort the database transaction,
- // which will discard any changes we made.
- }
- }
-
- originalArea = ref.originalArea;
-
- err2 = MNSCloseDatabase(&ref, err == noErr);
- if (err == noErr) {
- err = err2;
- }
-
- // The entity was created in a temporary area. After we close
- // that area, that temporary entity goes away, being replaced by
- // the final entity in the real area. To avoid client confusion,
- // we set the returned entity's area to that original area.
- // Otherwise, when they pass this returned entity to
- // the get or set routine, Network Setup will complain that
- // the entity's area doesn't exist.
-
- if (err == noErr) {
- destConfig->cookie2.fLoc = originalArea;
- }
- }
-
- // Clean up.
-
- if (packedPrefs != nil) {
- DisposeHandle(packedPrefs);
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- static OSStatus DuplicateConfigurationDatabase(const NSHConfigurationEntry *config,
- ConstStr255Param newConfigName,
- NSHConfigurationEntry *createdConfig)
- // Implementation of NSHDuplicateConfiguration which uses the Network Setup
- // database. See NSHDuplicateConfiguration's comment in header
- // file for interface specification.
- //
- // This routine opens up the database, creates an entity, and sets
- // the contents of the entity by duplicating the entity referenced
- // by config. And then there's a bunch of housekeeping.
- {
- OSStatus err;
- OSStatus err2;
- NSHConfigurationEntry tmpConfig;
- NSHConfigurationEntry *destConfig;
- MNSDatabaseRef ref;
- CfgAreaID originalArea;
-
- MoreAssertQ(config != nil);
- MoreAssertQ(newConfigName != nil);
-
- // createdConfig is an optional parameter. To simplify our
- // code, we use a temporary config if the user didn't supply it.
-
- if (createdConfig != nil) {
- destConfig = createdConfig;
- } else {
- destConfig = &tmpConfig;
- }
-
- err = MNSOpenDatabase(&ref, true);
- if (err == noErr) {
- FillOutConfigBits(config->cookie3.fType, newConfigName, destConfig);
-
- // Create the entity, getting back the CfgEntityRef.
-
- err = OTCfgCreateEntity(ref.dbRef, ref.area, &destConfig->cookie3,
- &destConfig->cookie2);
- if (err == noErr) {
- err = OTCfgDuplicateEntity(ref.dbRef, &config->cookie2, &destConfig->cookie2);
- if (err == noErr) {
- // Force the user-visible name to newConfigName.
- err = MNSSetPref(&ref, &destConfig->cookie2, kOTCfgUserVisibleNamePref, newConfigName, *newConfigName + 1);
- }
-
- if (err != noErr) {
- // There is no need to delete the half-created config
- // because we're about to abort the database transaction,
- // which will discard any changes we made.
- }
- }
-
- originalArea = ref.originalArea;
-
- err2 = MNSCloseDatabase(&ref, err == noErr);
- if (err == noErr) {
- err = err2;
- }
-
- // The entity was created in a temporary area. After we close
- // that area, that temporary entity goes away, being replaced by
- // the final entity in the real area. To avoid client confusion,
- // we set the returned entity's area to that original area.
- // Otherwise, when they pass this returned entity to
- // the get or set routine, Network Setup will complain that
- // the entity's area doesn't exist.
-
- if (err == noErr) {
- destConfig->cookie2.fLoc = originalArea;
- }
- }
-
- return err;
- }
-
- static OSStatus GetConfigurationDatabase(const NSHConfigurationEntry *config,
- NSHConfigurationDigest *configurationDigest)
- // Implementation of NSHGetConfiguration which uses the Network Setup
- // database. See NSHGetConfiguration's comment in header
- // file for interface specification.
- //
- // This routine opens up the database, reads the preferences out of
- // the configuration, and then converts them to a configuration digest.
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabaseRef ref;
- Handle packedPrefs;
-
- MoreAssertQ(config != nil);
- MoreAssertQ(configurationDigest != nil);
-
- packedPrefs = nil;
-
- err = MNSOpenDatabase(&ref, false);
- if (err == noErr) {
- err = ReadPackedPrefsFromDatabase(&ref, &config->cookie2, &packedPrefs);
- if (err == noErr) {
- err = BuildConfigurationDigestFromPackedPrefs(config->cookie4, packedPrefs, configurationDigest);
- }
-
- err2 = MNSCloseDatabase(&ref, false);
- if (err == noErr) {
- err = err2;
- }
- }
-
- if (packedPrefs != nil) {
- DisposeHandle(packedPrefs);
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- static void FixClientEntityForWriting(const MNSDatabaseRef *ref, const CfgEntityRef *clientEntity,
- CfgEntityRef *fixedEntity)
- // Entitys, as we expose them to the outside world, always
- // refer to the read area of the database. But if we've opened
- // this area for writing, we're actually supposed to write to
- // a temporary writable area. But the incoming entity references
- // from the client refer to the read area. This routine
- // creates a fixed entity which is entirely based on the
- // incoming client entity except that it refers to the write
- // area we've just opened.
- {
- MoreAssertQ(clientEntity->fLoc == ref->originalArea);
- *fixedEntity = *clientEntity;
- fixedEntity->fLoc = ref->area;
- }
-
- static OSStatus SetConfigurationDatabase(const NSHConfigurationEntry *config,
- const NSHConfigurationDigest *configurationDigest)
- // Implementation of NSHSetConfiguration which uses the Network Setup
- // database. See NSHSetConfiguration's comment in header
- // file for interface specification.
- //
- // This routine opens up the database and then sets the configuration
- // from the digest using using common utility routines
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabaseRef ref;
- CfgEntityRef tmpEntity;
- Handle packedPrefs;
-
- MoreAssertQ(config != nil);
- MoreAssertQ(configurationDigest != nil);
-
- packedPrefs = nil;
-
- err = MNSOpenDatabase(&ref, true);
- if (err == noErr) {
- FixClientEntityForWriting(&ref, &config->cookie2, &tmpEntity);
- err = BuildPackedPrefsFromConfigurationDigest(configurationDigest, false, &packedPrefs);
- if (err == noErr) {
- err = WritePackedPrefsToDatabase(&ref, &tmpEntity, packedPrefs);
- }
-
- err2 = MNSCloseDatabase(&ref, err == noErr);
- if (err == noErr) {
- err = err2;
- }
- }
-
- // Clean up.
-
- if (packedPrefs != nil) {
- DisposeHandle(packedPrefs);
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- // The DeleteConfigFromSetParam data structure is used
- // to pass parameters to DeleteConfigFromSetIterator.
-
- enum {
- kDeleteConfigFromSetParamSignature = 'DcSp'
- };
-
- struct DeleteConfigFromSetParam {
- OSType signature; // is always kDeleteConfigFromSetParamSignature, debugging check
- CfgEntityRef *entityWereDeleting;
- CfgSetsVector **newSetsVector;
- OSStatus latchedError;
- Boolean dirty;
- Boolean newSetContainsAppleTalk;
- Boolean newSetContainsTCPv4;
- Boolean newSetContainsRemote;
- Boolean newSetContainsModem;
- Boolean newSetContainsInfrared;
- };
- typedef struct DeleteConfigFromSetParam DeleteConfigFromSetParam;
-
- static void InitDeleteConfigFromSetParam(DeleteConfigFromSetParam *param, CfgEntityRef *entityToDelete, CfgSetsVector **newSetsVector)
- // This routine initialises the DeleteConfigFromSetParam
- // data structure.
- {
- param->signature = kDeleteConfigFromSetParamSignature;
- param->entityWereDeleting = entityToDelete;
- param->newSetsVector = newSetsVector;
- param->latchedError = noErr;
- param->dirty = false;
- param->newSetContainsAppleTalk = false;
- param->newSetContainsTCPv4 = false;
- param->newSetContainsRemote = false;
- param->newSetContainsModem = false;
- param->newSetContainsInfrared = false;
- }
-
- static pascal void DeleteConfigFromSetIterator(const MNSDatabaseRef *ref, CfgSetsElement *thisElement, void *p)
- // This routine is an iterator passed to MNSIterateSet. MNSIterateSet
- // repeatedly calls this routine, once for each element of the set.
- // The purpose of the routine is to:
- //
- // a) build a new set which contains all of the entities
- // in the existing set except for the one we're deleting, and
- // b) ensure that the new set has an entity for each of the various
- // backward compatibility protocols. If it does, we set the
- // appropriate Boolean flag in the DeleteConfigFromSetParam passed
- // in as the "p" parameter.
- //
- // The reason why we need to do this is explained in the comment
- // for DeleteConfigurationDatabase.
- {
- OSStatus err;
- DeleteConfigFromSetParam *param;
- #pragma unused(ref)
-
- param = (DeleteConfigFromSetParam *) p;
- MoreAssertQ(param != nil);
- MoreAssertQ(param->signature == kDeleteConfigFromSetParamSignature);
-
- if (param->latchedError == noErr) {
- if ( ! OTCfgIsSameEntityRef(&thisElement->fEntityRef, param->entityWereDeleting, kOTCfgIgnoreArea) ) {
- // This entity isn't the one we're deleting, so copy it across to
- // newSetsVector and, if it's an entity for a protocol which has
- // a legacy prefs file, mark it as existing in the new set.
-
- err = PtrAndHand(thisElement, (Handle) param->newSetsVector, sizeof(*thisElement));
- if (err == noErr) {
- (**(param->newSetsVector)).fCount += 1;
- switch (thisElement->fEntityInfo.fType) {
- case kOTCfgTypeAppleTalk: param->newSetContainsAppleTalk = true; break;
- case kOTCfgTypeTCPv4: param->newSetContainsTCPv4 = true; break;
- case kOTCfgTypeRemote: param->newSetContainsRemote = true; break;
- case kOTCfgTypeModem: param->newSetContainsModem = true; break;
- case kOTCfgTypeInfrared: param->newSetContainsInfrared = true; break;
- }
- }
- param->latchedError = err;
- } else {
- // This entity is the one we're deleting, so don't copy it, and mark
- // the newSetsVector as dirty so that we write it back.
- param->dirty = true;
- }
- }
- }
-
- static OSStatus DeleteConfigurationDatabase(const NSHConfigurationEntry *config)
- // Implementation of NSHDeleteConfiguration which uses the Network Setup
- // database. See NSHDeleteConfiguration's comment in header
- // file for interface specification.
- //
- // At first glance, this should be easy, ie a straight pass through to
- // OTCfgDeleteEntity. But then you have to worry about sets. If any
- // set contains a reference to this entity, you have to delete that
- // reference out of the set. And then you have to worry about
- // backward compatibility. What happens if you delete the TCP/IP
- // configuration out of the active set? When Network Setup goes
- // to export the database to the legacy preferences file, what
- // does it do if there's no active TCP/IP configuration. The answer:
- // it messes up horribly. So we prevent you from deleting an entity
- // if it's the last entity for a backward compatibility protocol.
- //
- // [Should this continue "... in the active set." I don't think
- // so, because we want to allow folks to switch sets easily, and having
- // them worry about "Oh, this set doesn't have a Remote Access entity
- // so I can't switch to it." is asking too much.]
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabaseRef ref;
- CfgEntityRef entityToDelete;
- ItemCount entityCount;
- CfgEntityRef *entityRefs;
- ItemCount entityIndex;
- CfgSetsVector **newSetsVector;
- DeleteConfigFromSetParam param;
-
- MoreAssertQ(config != nil);
-
- entityRefs = nil;
- newSetsVector = (CfgSetsVector **) NewHandle(sizeof(UInt32));
- err = MemError();
-
- if (err == noErr) {
- err = MNSOpenDatabase(&ref, true);
- }
- if (err == noErr) {
- FixClientEntityForWriting(&ref, &config->cookie2, &entityToDelete);
-
- // Cool. I don't have to worry about which order to delete
- // in (ie should I delete the entity or modify the set vectors
- // first) and how I roll back the changes in the case of a failure,
- // because changes are committed atomically by MNSCloseDatabase.
-
- // Delete the entity...
-
- if (err == noErr) {
- err = OTCfgDeleteEntity(ref.dbRef, &entityToDelete);
- }
-
- // Now remove it from any sets. First get the list of sets...
-
- if (err == noErr) {
- err = MNSGetEntitiesList(&ref,
- kOTCfgClassSetOfSettings, kOTCfgTypeSetOfSettings,
- &entityCount,
- &entityRefs, nil);
- }
-
- if (err == noErr) {
-
- // Then, for each set entity we found...
-
- for (entityIndex = 0; entityIndex < entityCount; entityIndex++) {
-
- // Set up newSetsVector to be an empty CfgSetsVector,
- // ie a handle with a 4 byte fCount field which is set
- // to 0.
-
- SetHandleSize( (Handle) newSetsVector, sizeof(UInt32));
- err = MemError();
- if (err == noErr) {
- (**newSetsVector).fCount = 0;
-
- // Fill out param, which is a parameter block containing
- // all the information that DeleteConfigFromSetIterator needs.
-
- InitDeleteConfigFromSetParam(¶m, &entityToDelete, newSetsVector);
-
- // Call DeleteConfigFromSetIterator on each element of
- // the entityIndex'th set entity.
-
- err = MNSIterateSet(&ref,
- &entityRefs[entityIndex],
- DeleteConfigFromSetIterator, ¶m,
- false);
- if (err == noErr) {
- err = param.latchedError;
- }
- }
- if (err == noErr && param.dirty) {
- if (param.newSetContainsAppleTalk
- && param.newSetContainsTCPv4
- && param.newSetContainsRemote
- && param.newSetContainsModem
- && param.newSetContainsInfrared) {
- err = MNSSetPrefHandle(&ref, &entityRefs[entityIndex], kOTCfgSetsVectorPref, (Handle) newSetsVector);
- } else {
- err = -11;
- }
- }
- if (err != noErr) {
- break;
- }
- }
- }
-
- err2 = MNSCloseDatabase(&ref, err == noErr);
- if (err == noErr) {
- err = err2;
- }
- }
-
- // Clean up.
-
- if (newSetsVector != nil) {
- DisposeHandle( (Handle) newSetsVector );
- MoreAssertQ(MemError() == noErr);
- }
- if (entityRefs != nil) {
- DisposePtr( (Ptr) entityRefs );
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- static OSStatus RenameConfigurationDatabase(const NSHConfigurationEntry *config,
- ConstStr255Param newConfigName,
- NSHConfigurationEntry *newConfig)
- // Implementation of NSHRenameConfiguration which uses the Network Setup
- // database. See NSHRenameConfiguration's comment in header
- // file for interface specification.
- //
- // A relatively simple pass through to OTCfgSetEntityName.
- {
- OSStatus err;
- OSStatus err2;
- NSHConfigurationEntry tmpConfig;
- NSHConfigurationEntry *destConfig;
- MNSDatabaseRef ref;
- CfgEntityRef tmpEntity;
-
- MoreAssertQ(config != nil);
- MoreAssertQ(newConfigName != nil);
-
- if (newConfig != nil) {
- destConfig = newConfig;
- } else {
- destConfig = &tmpConfig;
- }
-
- err = MNSOpenDatabase(&ref, true);
- if (err == noErr) {
- FillOutConfigBits(config->cookie3.fType, newConfigName, destConfig);
-
- FixClientEntityForWriting(&ref, &config->cookie2, &tmpEntity);
- err = OTCfgSetEntityName(ref.dbRef, &tmpEntity, newConfigName, &destConfig->cookie2);
-
- err2 = MNSCloseDatabase(&ref, err == noErr);
- if (err == noErr) {
- err = err2;
- }
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Internet Setup using File ------
-
- static OSStatus ReadPackedPrefsFromFile(SInt16 configID, Handle *packedPrefs)
- // This routine builds a packed preference handle based on
- // all the preferences in the specified configuration of the
- // current resource file. *packedPrefs must be nil before you call
- // the routine. The routine either succeeds (returning noErr
- // and setting *packedPrefs to a valid handle), or fails
- // (returning an error, and leaving *packedRefs as nil).
- {
- OSStatus err;
- OSStatus err2;
- PrefBuilderState state;
- SInt16 typeCount;
- SInt16 typeIndex;
- OSType thisType;
- Handle thisResourceH;
- SInt16 junkID;
- OSType junkType;
- Str255 configName;
-
- MoreAssertQ(packedPrefs != nil);
- MoreAssertQ(*packedPrefs == nil);
-
- BuilderNew(&state);
-
- // Iterate through all the resource types in the file.
- // For each type, check to see whether there's a resource
- // with ID equal to configID in the file. If there is,
- // add it to the packedPrefs.
-
- typeCount = Count1Types();
- err = ResError();
- if (err == noErr) {
- for (typeIndex = 1; typeIndex <= typeCount; typeIndex++) {
- Get1IndType(&thisType, typeIndex);
- err = ResError();
- if (err == noErr) {
- thisResourceH = Get1Resource(thisType, configID);
- err = CheckResError(thisResourceH);
- if (err == noErr) {
- HLock(thisResourceH);
-
- // We have to handle the 'cnam' as a special case. In
- // legacy files, the user-visible name of the preference
- // is stored in the resource name of the 'cnam' preference.
- // The preference data contains no useful information.
- // So when we encounter a 'cnam' preference, we extract
- // the resource name and write that to the packed prefs
- // as a 'pnam' preference. This is where the various
- // digest routines expect the user-visible name to be.
- // In addition, WritePackedPrefsToFile is smart enough to
- // undo this.
-
- if (thisType == kOTCfgCompatNamePref) {
- GetResInfo(thisResourceH, &junkID, &junkType, configName);
- BuilderNewPref(&state, kOTCfgUserVisibleNamePref, configName, configName[0] + 1);
- } else {
- BuilderNewPref(&state, thisType, *thisResourceH, GetHandleSize(thisResourceH));
- }
-
- // ••• Gotcha •••
- // Release the resource we just got. This was a contentious
- // issue when coding this. We want to release the resource because
- // it avoids the resources building up in the memory of the client
- // application. But what happens if the resource file
- // is being used by other code (ie someone else in this
- // process has the file open read/write, so we're sharing
- // a resource map with them) and we release the resource
- // out from underneath them. The answer is, of course,
- // "bad things", but we have no way of detecting this condition.
- // I'm just making the assumption that this situation won't
- // happen. As it is, it's fairly unlikely. Most software
- // that modifies preferences (most importantly the network
- // control panels) runs as a separate process, so resource
- // map sharing is unlikely. It could happen if you're running
- // an extension inside the context of one of those applications,
- // but doing that is asking for trouble anyway (-:
- //
- // For more background on this problem. see the comment about
- // fsRdWrPerm in OpenNetworkPrefFile.
- //
- // One added advantage to releasing the resource is that we
- // can simply HLock the handle above, rather than using the
- // state HGetState/HLock/HSetState tuple.
- //
- // -- Quinn, 25 May 1999
-
- ReleaseResource(thisResourceH);
- err = ResError();
- } else if (err == resNotFound) {
- err = noErr;
- }
- }
- if (err != noErr) {
- break;
- }
- }
- }
-
- err2 = BuilderDone(&state, packedPrefs);
- if (err == noErr) {
- err = err2;
- }
- MoreAssertQ(err != noErr && packedPrefs == nil || err == noErr && packedPrefs != nil);
- return err;
- }
-
- static OSStatus Set1ResourceFromPtr(OSType theType, SInt16 theID, void *dataPtr, ByteCount dataSize)
- // God I hate the Resource Manager API. There's no
- // simple way of saying "set this resource to this value".
- // Instead, you have to get it, see whether it exists,
- // if it does, change it and mark it changed, if it doesn't,
- // create it. Blurgh. All the while checking for weirdo
- // errors and handling the facts that a) you can't release
- // changed resources (otherwise there's no copy of the handle
- // containing the data for the Resource Manager to write
- // when you call UpdateResFile), and b) AddResource converts
- // a memory handle to a resource handle, but if it fails you
- // still have to dispose of the memory.
- {
- OSStatus err;
- Handle thisResourceH;
- Handle tmpDataH;
-
- thisResourceH = Get1Resource(theType, theID);
- err = CheckResError(thisResourceH);
- if (err == noErr) {
- err = PtrToXHand(dataPtr, thisResourceH, dataSize);
- if (err == noErr) {
- ChangedResource(thisResourceH);
- err = ResError();
- }
- } else if (err == resNotFound) {
- err = PtrToHand(dataPtr, &tmpDataH, dataSize);
- if (err == noErr) {
- AddResource(tmpDataH, theType, theID, "\p");
- err = ResError();
- if (err != noErr) {
- DisposeHandle(tmpDataH);
- MoreAssertQ(MemError() == noErr);
- }
- }
- }
-
- return err;
- }
-
- static OSStatus WritePackedPrefsToFile(OSType protocol, SInt16 configID, Handle packedPrefs)
- // This is a utility routine that simply writes the entire
- // set of packed preferences to the configuration specified
- // by configID of the current resource file.
- {
- OSStatus err;
- SInt8 s;
- ByteCount cookie;
- OSType prefType;
- ByteCount prefSize;
- void *prefPtr;
- Handle cnamHandle;
-
- MoreAssertQ(packedPrefs != nil);
-
- // Lock down the packed preferences.
-
- s = HGetState(packedPrefs);
- HLock(packedPrefs);
- MoreAssertQ(MemError() == noErr);
-
- // Iterate through each preference, write it out to the database.
-
- err = noErr;
- cookie = 0;
- do {
- WriterGetNextPref(&cookie, *packedPrefs, &prefType, &prefPtr, &prefSize);
- switch (prefType) {
- case kOTCfgUserVisibleNamePref:
-
- // We have to handle the 'pnam' preference as a special
- // case. In legacy files, the user-visible name of the
- // configuration is stored as the resource name of the
- // 'cnam' resource. So we need to first write a 'cnam'
- // resource then change its name to the name given as the
- // value of the 'pnam' preference.
-
- // ••• Gotcha •••
- // The following switch is a bit of a hack. It seems that
- // the OT preference files use a slightly different format
- // from the Remote Access files. Specifically, ARA puts
- // the configuration ID of the configuration into the
- // resource data of the 'cnam' resource, but OT preference
- // files leave the 'cnam' resource empty. I'm faithfully
- // emulating this behaviour, even though I'm pretty sure that
- // ARA doesn't care about the contents of the resource
- // (I've seen plenty of preference files where the resource
- // contents is wrong and ARA still seems to work) primarily
- // to prevent the legacy file format drifting any further
- // than it also has. I default to the OT mechanism because
- // I'm pretty sure that no one else is going to depend on this.
-
- switch (protocol) {
- case kOTCfgTypeRemote:
- case kOTCfgTypeModem:
- err = Set1ResourceFromPtr(kOTCfgCompatNamePref, configID, &configID, sizeof(configID));
- break;
- default:
- err = Set1ResourceFromPtr(kOTCfgCompatNamePref, configID, &configID, 0);
- break;
- }
-
- // Now update the resource name with the user-visible name
- // of the configuration.
-
- if (err == noErr) {
- cnamHandle = Get1Resource(kOTCfgCompatNamePref, configID);
- // Assert: We just created this resource, where did it go!
- MoreAssertQ( CheckResError(cnamHandle) == noErr );
- if (cnamHandle != nil) {
- // Assert: prefPtr should point to a Pascal string.
- MoreAssertQ( *((UInt8 *) prefPtr) + 1 == prefSize );
- SetResInfo(cnamHandle, configID, prefPtr);
- }
- }
- break;
- case 0:
- // do nothing, termination condition
- break;
- default:
- err = Set1ResourceFromPtr(prefType, configID, prefPtr, prefSize);
- break;
- }
- } while (err == noErr && prefType != 0);
-
- // Clean up.
-
- HSetState(packedPrefs, s);
-
- return err;
- }
-
- static SInt16 GenerateUniqueNewConfigID(void)
- // Generate a unique ID for the new configuration. The loop
- // might seem a bit gung ho, but it's actually fairly fail secure.
- // As a rule, if it fails Get1Resource will return nil, and we
- // fall out.
- {
- SInt16 newConfigID;
-
- newConfigID = 128;
- while ( Get1Resource(kOTCfgCompatNamePref, newConfigID) != nil ) {
- newConfigID += 1;
- }
- return newConfigID;
- }
-
- static void DeleteHalfCreatedConfig(Handle packedPrefs, SInt16 configID)
- // If we get halfway through creating a configuration and fail,
- // we have to make sure there aren't any bits of the new configuration
- // left lying around in the preferences file. This routine does this.
- // It shares a lot of code with DeleteConfigurationFile, but not
- // really enough to justify one calling the other. The key differences
- // are: a) this routine assumes the preference file is already open, and
- // b) this routine doesn't raise an error if the preference doesn't exist.
- {
- OSStatus err;
- UInt32 cookie;
- OSType prefType;
- void *junkPtr;
- ByteCount junkSize;
- Handle prefToDelete;
-
- err = noErr;
- cookie = 0;
- do {
- WriterGetNextPref(&cookie, *packedPrefs, &prefType, &junkPtr, &junkSize);
- if (prefType != 0) {
- if (prefType == kOTCfgUserVisibleNamePref) {
- prefType = kOTCfgCompatNamePref;
- }
- SetResLoad(false);
- prefToDelete = Get1Resource(prefType, configID);
- err = CheckResError(prefToDelete);
- SetResLoad(true);
-
- if (err == noErr) {
- RemoveResource(prefToDelete);
- err = ResError();
- if (err == noErr) {
- DisposeHandle(prefToDelete);
- MoreAssertQ(MemError() == noErr);
- }
- } else if (err == resNotFound) {
- err = noErr;
- }
- }
- } while (err == noErr && prefType != 0);
- MoreAssertQ(err == noErr);
- }
-
- static OSStatus CreateConfigurationFile(const NSHConfigurationDigest *configurationDigest,
- NSHConfigurationEntry *createdConfig)
- // Implementation of NSHCreateConfiguration which uses the legacy
- // preference files. See NSHCreateConfiguration's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- SInt16 oldResFile;
- SInt16 refNum;
- SInt16 newConfigID;
- Handle packedPrefs;
-
- MoreAssertQ(configurationDigest != nil);
-
- packedPrefs = nil;
-
- err = OpenNetworkPrefFile(configurationDigest->fCommon.fProtocol, fsRdWrPerm, &oldResFile, &refNum);
- if (err == noErr) {
- newConfigID = GenerateUniqueNewConfigID();
-
- // Fill out the entity with the information from the digest.
-
- err = BuildPackedPrefsFromConfigurationDigest(configurationDigest, true, &packedPrefs);
- if (err == noErr) {
- err = WritePackedPrefsToFile(configurationDigest->fCommon.fProtocol, newConfigID, packedPrefs);
- if (err != noErr) {
- // If we get an error, make sure to eelete any bits of the
- // half-created config.
- DeleteHalfCreatedConfig(packedPrefs, newConfigID);
- }
- }
-
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- // If the client requested the NSHConfigurationEntry for the new
- // configuration, give it to them.
-
- if (err == noErr && createdConfig != nil) {
- OTMemzero(createdConfig, sizeof(*createdConfig));
- BlockMoveData(configurationDigest->fCommon.fConfigName, createdConfig->name, sizeof(createdConfig->name));
- createdConfig->cookie = newConfigID;
- createdConfig->cookie4 = configurationDigest->fCommon.fProtocol;
- }
-
- // Clean up.
-
- if (packedPrefs != nil) {
- DisposeHandle(packedPrefs);
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- static OSStatus DuplicateConfigurationFile(const NSHConfigurationEntry *config,
- ConstStr255Param newConfigName,
- NSHConfigurationEntry *createdConfig)
- // Implementation of NSHDuplicateConfiguration which uses the legacy
- // preference files. See NSHDuplicateConfiguration's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- SInt16 oldResFile;
- SInt16 refNum;
- Handle packedPrefs;
- SInt16 newConfigID;
- Handle cnamHandle;
-
- MoreAssertQ(config != nil);
- MoreAssertQ(newConfigName != nil);
-
- packedPrefs = nil;
-
- err = OpenNetworkPrefFile(config->cookie4, fsRdWrPerm, &oldResFile, &refNum);
- if (err == noErr) {
- newConfigID = GenerateUniqueNewConfigID();
-
- // Read the preferences from the original configuration
- // and write them to the new configuration.
-
- if (err == noErr) {
- err = ReadPackedPrefsFromFile(config->cookie, &packedPrefs);
- }
- if (err == noErr) {
- err = WritePackedPrefsToFile(config->cookie4, newConfigID, packedPrefs);
- }
-
- // Set the name of the new configuration.
-
- if (err == noErr) {
- cnamHandle = Get1Resource(kOTCfgCompatNamePref, newConfigID);
- err = CheckResError(cnamHandle);
- if (err == noErr) {
- SetResInfo(cnamHandle, newConfigID, newConfigName);
- }
- }
-
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- // If the client requested the NSHConfigurationEntry for the new
- // configuration, give it to them.
-
- if (err == noErr && createdConfig != nil) {
- *createdConfig = *config;
- BlockMoveData(newConfigName, createdConfig->name, sizeof(createdConfig->name));
- createdConfig->cookie = newConfigID;
- }
-
- // Clean up.
-
- if (packedPrefs != nil) {
- DisposeHandle(packedPrefs);
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- static OSStatus GetConfigurationFile(const NSHConfigurationEntry *config,
- NSHConfigurationDigest *configurationDigest)
- // Implementation of NSHGetConfiguration which uses the legacy
- // preference files. See NSHGetConfiguration's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- SInt16 oldResFile;
- SInt16 refNum;
- Handle packedPrefs;
-
- MoreAssertQ(config != nil);
- MoreAssertQ(configurationDigest != nil);
-
- packedPrefs = nil;
-
- err = OpenNetworkPrefFile(config->cookie4, fsRdWrPerm, &oldResFile, &refNum);
- if (err == noErr) {
- err = ReadPackedPrefsFromFile(config->cookie, &packedPrefs);
- if (err == noErr) {
- err = BuildConfigurationDigestFromPackedPrefs(config->cookie4, packedPrefs, configurationDigest);
- }
-
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- if (packedPrefs != nil) {
- DisposeHandle(packedPrefs);
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- static OSStatus SetConfigurationFile(const NSHConfigurationEntry *config,
- const NSHConfigurationDigest *configurationDigest)
- // Implementation of NSHSetConfiguration which uses the legacy
- // preference files. See NSHSetConfiguration's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- SInt16 oldResFile;
- SInt16 refNum;
- Handle packedPrefs;
- SInt16 currentConfigID;
-
- MoreAssertQ(config != nil);
- MoreAssertQ(configurationDigest != nil);
-
- packedPrefs = nil;
-
- err = OpenNetworkPrefFile(config->cookie4, fsRdWrPerm, &oldResFile, &refNum);
- if (err == noErr) {
- err = BuildPackedPrefsFromConfigurationDigest(configurationDigest, false, &packedPrefs);
- if (err == noErr) {
- err = WritePackedPrefsToFile(config->cookie4, config->cookie, packedPrefs);
- }
-
- // If we're modifying the current configuration, tell the protocol
- // stacks about it.
-
- if (err == noErr) {
- err = GetCurrentConfigFromPrefFile(¤tConfigID);
- if (err == noErr) {
- if (config->cookie == currentConfigID) {
- err = CommitChangesToPrefFile(config->cookie4, refNum, config->cookie);
- }
- }
- }
-
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- // Clean up.
-
- if (packedPrefs != nil) {
- DisposeHandle(packedPrefs);
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- static OSStatus DeleteConfigurationFile(const NSHConfigurationEntry *config)
- // Implementation of NSHDeleteConfiguration which uses the legacy
- // preference files. See NSHDeleteConfiguration's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- SInt16 oldResFile;
- SInt16 refNum;
- SInt16 currentConfigID;
- Handle packedPrefs;
- UInt32 cookie;
- OSType prefType;
- void *junkPtr;
- ByteCount junkSize;
- Handle prefToDelete;
-
- MoreAssertQ(config != nil);
-
- packedPrefs = nil;
-
- err = OpenNetworkPrefFile(config->cookie4, fsRdWrPerm, &oldResFile, &refNum);
- if (err == noErr) {
-
- // You're not allowed to delete an active configuration.
-
- err = GetCurrentConfigFromPrefFile(¤tConfigID);
- if (err == noErr) {
- if (config->cookie == currentConfigID) {
- err = -11;
- }
- }
-
- // Now read a slice out of the preference file, ie all
- // the resource with ID of config->cookie regardless of their
- // type. We do this in before starting to delete stuff because
- // a) we already have the code (we share it with various other
- // routines) and b) the API to the Resource Manager is based
- // on indexes, so if you start deleting stuff midway through
- // things get very confusing.
- //
- // This wastes some memory (we read in all the preference data
- // even though we're never going to use it), but that's the price
- // you pay for having me write the code for you (-:
-
- if (err == noErr) {
- err = ReadPackedPrefsFromFile(config->cookie, &packedPrefs);
- }
-
- // Now delete each preference in the slice from the resource file.
- // We exercise two little known Resource Manager features here.
- // Firstly, we SetResLoad to false before calling Get1Resource.
- // This saves memory (and time) by preventing the Resource Manager
- // from actually loading the preference data into memory.
- // Secondly, we must DisposeHandle(prefToDelete) after we've
- // successfully removed it from the resource file. Removing
- // a handle from a resource file leaves you with a memory
- // handle which you must dispose lest you leak.
-
- if (err == noErr) {
- HLock(packedPrefs); // Unilaterally lock because we're going to dispose at the end of this routine anyway.
- cookie = 0;
- do {
- WriterGetNextPref(&cookie, *packedPrefs, &prefType, &junkPtr, &junkSize);
- if (prefType != 0) {
- if (prefType == kOTCfgUserVisibleNamePref) {
- prefType = kOTCfgCompatNamePref;
- }
- SetResLoad(false);
- prefToDelete = Get1Resource(prefType, config->cookie);
- err = CheckResError(prefToDelete);
- SetResLoad(true);
-
- if (err == noErr) {
- RemoveResource(prefToDelete);
- err = ResError();
- }
- if (err == noErr) {
- DisposeHandle(prefToDelete);
- MoreAssertQ(MemError() == noErr);
- }
- }
- } while (err == noErr && prefType != 0);
- }
-
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- // Clean up.
-
- if (packedPrefs != nil) {
- DisposeHandle(packedPrefs);
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- static OSStatus RenameConfigurationFile(const NSHConfigurationEntry *config,
- ConstStr255Param newConfigName,
- NSHConfigurationEntry *newConfig)
- // Implementation of NSHRenameConfiguration which uses the legacy
- // preference files. See NSHRenameConfiguration's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- SInt16 oldResFile;
- SInt16 refNum;
- Handle cnamHandle;
-
- MoreAssertQ(config != nil);
- MoreAssertQ(newConfigName != nil);
-
- err = OpenNetworkPrefFile(config->cookie4, fsRdWrPerm, &oldResFile, &refNum);
- if (err == noErr) {
- cnamHandle = Get1Resource(kOTCfgCompatNamePref, config->cookie);
- err = CheckResError(cnamHandle);
- if (err == noErr) {
- SetResInfo(cnamHandle, config->cookie, newConfigName);
- }
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- // If the client requested the NSHConfigurationEntry for the renamed
- // configuration, give it to them.
-
- if (err == noErr && newConfig != nil) {
- *newConfig = *config;
- BlockMoveData(newConfigName, newConfig->name, sizeof(newConfig->name));
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Internet Setup Abstraction ------
-
- extern pascal OSStatus NSHCreateConfiguration(const NSHConfigurationDigest *configurationDigest,
- NSHConfigurationEntry *createdConfig)
- // See comments in interface part.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = CreateConfigurationDatabase(configurationDigest, createdConfig);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = CreateConfigurationFile(configurationDigest, createdConfig);
- }
- return err;
- }
-
- extern pascal OSStatus NSHDuplicateConfiguration(NSHConfigurationEntry *config,
- ConstStr255Param newConfigName,
- NSHConfigurationEntry *createdConfig)
- // See comments in interface part.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = DuplicateConfigurationDatabase(config, newConfigName, createdConfig);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = DuplicateConfigurationFile(config, newConfigName, createdConfig);
- }
- return err;
- }
-
- extern pascal OSStatus NSHGetConfiguration(const NSHConfigurationEntry *config,
- NSHConfigurationDigest *configurationDigest)
- // See comments in interface part.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = GetConfigurationDatabase(config, configurationDigest);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = GetConfigurationFile(config, configurationDigest);
- }
- return err;
- }
-
- extern pascal OSStatus NSHSetConfiguration(const NSHConfigurationEntry *config,
- const NSHConfigurationDigest *configurationDigest)
- // See comments in interface part.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = SetConfigurationDatabase(config, configurationDigest);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = SetConfigurationFile(config, configurationDigest);
- }
- return err;
- }
-
- extern pascal OSStatus NSHDeleteConfiguration(const NSHConfigurationEntry *config)
- // See comments in interface part.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = DeleteConfigurationDatabase(config);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = DeleteConfigurationFile(config);
- }
- return err;
- }
-
- extern pascal OSStatus NSHRenameConfiguration(const NSHConfigurationEntry *config,
- ConstStr255Param newConfigName,
- NSHConfigurationEntry *newConfig)
- // See comments in interface part.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = RenameConfigurationDatabase(config, newConfigName, newConfig);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = RenameConfigurationFile(config, newConfigName, newConfig);
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Database Will Dial ------
-
- static OSStatus GetPortNameFromTCPPrefs(Ptr buffer, SInt32 prefSize, char *portName)
- // This routine takes the address and size of an 'iitf' preference
- // and extracts the port name from the first interface.
- {
- OSStatus err;
- UInt16 interfaceCount;
- Ptr cursor;
- NSHTCPv4ConfigurationDigest firstInterface;
- UInt8 portNameLength;
-
- // Get the count of interfaces, checking for possibly bogus
- // preference data.
-
- err = noErr;
- if (prefSize < sizeof(UInt16)) {
- err = -1;
- }
- if (err == noErr) {
- interfaceCount = *((UInt16 *)buffer);
- if (interfaceCount < 1) {
- err = -1;
- }
- }
-
- // Unpack the first interface out of the 'iitf'.
-
- if (err == noErr) {
- cursor = buffer + sizeof(UInt16);
- UnpackTCPPrefs(&cursor, &firstInterface);
-
- // Assert: Did not consume correct number of bytes
- MoreAssertQ( interfaceCount > 1 || (cursor == buffer + prefSize) );
- }
-
- // Copy the port name out of the unpacked interface.
-
- if (err == noErr) {
- portNameLength = firstInterface.fHintPortName[0];
- if ( portNameLength > kMaxProviderNameLength) {
- err = -1;
- } else {
-
- // Poor Man's C2PString avoids me having to figure
- // out which wacky library CodeWarrior wants me to link with
- // today!
-
- BlockMoveData(firstInterface.fHintPortName + 1, portName, portNameLength);
- portName[ portNameLength ] = 0;
- }
- }
-
- return err;
- }
-
- static OSStatus GetInfoForTCPEntity(const MNSDatabaseRef *ref, const CfgEntityRef *entityID,
- Boolean *enabled, char *portName)
- // This routine returns the enabled status and port name
- // for the TCP/IP preferences entity described by entityID
- // in the ref database.
- {
- OSStatus err;
- SInt16 enabledInt;
- Ptr buffer;
- ByteCount prefSize;
-
- buffer = nil;
-
- // First return enabled using the simple API.
-
- err = MNSGetFixedSizePref(ref, entityID, kOTCfgTCPUnloadAttrPref, &enabledInt, sizeof(SInt16));
- if (err == noErr) {
- *enabled = (enabledInt != 3);
- }
-
- // Now return the port name. Now call the variable sized
- // API to get the 'iitf' resource and then extract the port name
- // from the preference buffer.
-
- if (err == noErr) {
- err = MNSGetPref(ref, entityID, kOTCfgTCPInterfacesPref, &buffer, &prefSize);
- }
- if (err == noErr) {
- err = GetPortNameFromTCPPrefs(buffer, prefSize, portName);
- }
-
- // Clean up.
-
- if (buffer != nil) {
- DisposePtr(buffer);
- MoreAssertQ(MemError() == noErr);
- }
- return err;
- }
-
- static OSStatus GetTCPInfoFromDatabase(Boolean *enabled, char *portName)
- // The high-level entry point into the configuration database
- // implementation. We open the database, find the current
- // TCP entity and read the info we need out of that entity.
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabaseRef ref;
- CfgEntityRef currentTCPEntity;
-
- err = MNSOpenDatabase(&ref, false);
- if (err == noErr) {
- err = FindCurrentConnection(&ref, kOTCfgTypeTCPv4, ¤tTCPEntity);
- if (err == noErr) {
- err = GetInfoForTCPEntity(&ref, ¤tTCPEntity, enabled, portName);
- }
-
- err2 = MNSCloseDatabase(&ref, false);
- if (err == noErr) {
- err = err2;
- }
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- File Will Dial ------
-
- static OSStatus GetTCPInfoFromFile(Boolean *enabled, char *portName)
- // This is the high-level entry point into the direct file
- // access implementation. It simply finds the preferences
- // file and reads the preferences out directly.
- {
- OSStatus err;
- OSStatus err2;
- SInt16 oldResFile;
- SInt16 refNum;
- Handle unldResource;
- Handle iitfResource;
- SInt8 s;
- SInt16 config;
-
- err = OpenNetworkPrefFile(kOTCfgTypeTCPv4, fsRdPerm, &oldResFile, &refNum);
- if (err == noErr) {
- err = GetCurrentConfigFromPrefFile(&config);
-
- if (err == noErr) {
- unldResource = Get1Resource(kOTCfgTCPUnloadAttrPref, config);
- err = CheckResError(unldResource);
- }
- if (err == noErr) {
- *enabled = ( **((SInt16 **) unldResource) != 3);
- }
-
- if (err == noErr) {
- iitfResource = Get1Resource(kOTCfgTCPInterfacesPref, config);
- err = CheckResError(iitfResource);
- }
-
- if (err == noErr) {
- s = HGetState(iitfResource);
- HLock(iitfResource);
- err = GetPortNameFromTCPPrefs(*iitfResource, GetHandleSize(iitfResource), portName);
- HSetState(iitfResource, s);
- }
-
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Will Dial Abstraction -----
-
- static OSStatus GetTCPInfo(Boolean *enabled, char *portName)
- // A dispatcher. If the config database is available,
- // we call it, otherwise we fall back to reading the
- // preferences file directly.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = GetTCPInfoFromDatabase(enabled, portName);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = GetTCPInfoFromFile(enabled, portName);
- }
- return err;
- }
-
- extern pascal OSStatus NSHTCPWillDial(UInt32 *willDial)
- // The main entry point. We call our core
- // implementation and then generate the result
- // based on the returned information.
- {
- OSStatus err;
- InetInterfaceInfo info;
- Boolean enabled;
- char currentPortName[kMaxProviderNameSize];
- OTPortRecord portRecord;
-
- MoreAssertQ(willDial != nil);
-
- *willDial = kNSHTCPDialUnknown;
-
- err = noErr;
- if ( kUseInetInterfaceInfo && OTInetGetInterfaceInfo(&info, kDefaultInetInterface) == noErr) {
-
- // The TCP/IP stack is already loaded. With the current
- // way TCP/IP is organised, the stack being loaded implies
- // that we're already dialled in.
-
- *willDial = kNSHTCPDialNo;
-
- } else {
- err = GetTCPInfo(&enabled, currentPortName);
- if (err == noErr) {
- if (enabled) {
- if ( OTStrEqual(currentPortName, "ddp") ) {
-
- // A special case for MacIP, because "ddp" does
- // not have an active port if AppleTalk is disabled.
-
- *willDial = kNSHTCPDialNo;
-
- } else if ( OTFindPort(&portRecord, currentPortName) ) {
-
- // We know the port. Look at the device type
- // to decide whether we might dial.
-
- switch ( OTGetDeviceTypeFromPortRef(portRecord.fRef) ) {
- case kOTADEVDevice:
- case kOTIRTalkDevice:
- case kOTSMDSDevice:
- // Assert: TCP shouldn't be using this link type
- MoreAssertQ(false);
- *willDial = kNSHTCPDialNo;
- break;
-
- case kOTISDNDevice:
- case kOTATMDevice:
- case kOTSerialDevice:
- case kOTModemDevice:
- // Assert: TCP shouldn't be using this link type
- MoreAssertQ(false);
- *willDial = kNSHTCPDialYes;
- break;
-
- case kOTEthernetDevice:
- // For Ethernet, special case AOL because, well, they're special.
- if ( OTStrEqual(currentPortName, "AOLLink0") ) {
- *willDial = kNSHTCPDialYes;
- } else {
- *willDial = kNSHTCPDialNo;
- }
- break;
-
- case kOTLocalTalkDevice:
- case kOTTokenRingDevice:
- case kOTFastEthernetDevice:
- case kOTFDDIDevice:
- case kOTIrDADevice:
- case kOTATMSNAPDevice:
- case kOTFibreChannelDevice:
- case kOTFireWireDevice:
- *willDial = kNSHTCPDialNo;
- break;
-
- case kOTMDEVDevice:
- case kOTSLIPDevice:
- case kOTPPPDevice:
- *willDial = kNSHTCPDialYes;
- break;
-
- default:
- MoreAssertQ(*willDial == kNSHTCPDialUnknown);
- break;
- }
- } else {
- err = -1;
- }
- } else {
- *willDial = kNSHTCPDialTCPDisabled;
- }
- }
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- DHCP Release -----
-
- static pascal OSStatus DHCPReleaseDatabase(void)
- // Implementation of NSHDHCPRelease which uses the Network Setup
- // database. See NSHDHCPRelease's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabaseRef ref;
- CfgEntityRef currentTCPEntity;
- OTCfgTCPUnloadAttr oldUnloadAttr;
- OTCfgTCPUnloadAttr newUnloadAttr;
- const UInt8 dummyPref[16] = {0};
-
- // Start by forcing the TCP/IP stack to unload (by deactivating it), saving
- // the old state in oldUnloadAttr.
-
- err = MNSOpenDatabase(&ref, true);
- if (err == noErr) {
- err = FindCurrentConnection(&ref, kOTCfgTypeTCPv4, ¤tTCPEntity);
- if (err == noErr) {
- err = MNSGetFixedSizePref(&ref, ¤tTCPEntity, kOTCfgTCPUnloadAttrPref, &oldUnloadAttr, sizeof(oldUnloadAttr));
- }
- if (err == noErr) {
- newUnloadAttr = kOTCfgTCPInactive;
- err = MNSSetPref(&ref, ¤tTCPEntity, kOTCfgTCPUnloadAttrPref, &newUnloadAttr, sizeof(newUnloadAttr));
- }
- err2 = MNSCloseDatabase(&ref, err == noErr);
- if (err == noErr) {
- err = err2;
- }
- }
-
- // Then reactive the TCP/IP stack, zeroing the 'dclt' preference in the process.
-
- if (err == noErr) {
- err = MNSOpenDatabase(&ref, true);
- if (err == noErr) {
- err = FindCurrentConnection(&ref, kOTCfgTypeTCPv4, ¤tTCPEntity);
- if (err == noErr) {
- newUnloadAttr = kOTCfgTCPInactive;
- err = MNSSetPref(&ref, ¤tTCPEntity, kOTCfgTCPUnloadAttrPref, &oldUnloadAttr, sizeof(oldUnloadAttr));
- }
- if (err == noErr) {
- err = MNSSetPref(&ref, ¤tTCPEntity, kOTCfgTCPDHCPLeaseInfoPref, dummyPref, sizeof(dummyPref));
- }
- err2 = MNSCloseDatabase(&ref, err == noErr);
- if (err == noErr) {
- err = err2;
- }
- }
- }
-
- return err;
- }
-
- static pascal OSStatus DHCPReleaseFile(void)
- // Implementation of NSHDHCPRelease which uses the legacy
- // preference files. See NSHDHCPRelease's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- SInt16 refNum;
- SInt16 oldResFile;
- OTCfgTCPUnloadAttr **unldResourceH;
- SInt16 config;
- OTCfgTCPUnloadAttr oldUnloadAttr;
- Handle dcltResourceH;
-
- err = OpenNetworkPrefFile(kOTCfgTypeTCPv4, fsRdWrPerm, &oldResFile, &refNum);
- if (err == noErr) {
- err = GetCurrentConfigFromPrefFile(&config);
-
- // Start by forcing the TCP/IP stack to unload (by deactivating it), saving
- // the old state in oldUnloadAttr.
-
- if (err == noErr) {
- unldResourceH = (OTCfgTCPUnloadAttr **) Get1Resource(kOTCfgTCPUnloadAttrPref, config);
- err = CheckResError(unldResourceH);
- }
- if (err == noErr && GetHandleSize( (Handle) unldResourceH) != sizeof(OTCfgTCPUnloadAttr)) {
- err = -1;
- }
- if (err == noErr) {
- oldUnloadAttr = **unldResourceH;
- **unldResourceH = kOTCfgTCPInactive;
- ChangedResource( (Handle) unldResourceH);
- err = ResError();
- if (err == noErr) {
- UpdateResFile(refNum);
- err = ResError();
- }
- if (err == noErr) {
- err = CommitChangesToPrefFile(kOTCfgTypeTCPv4, refNum, config);
- }
- }
-
- // ••• Gotcha •••
- // In some circumstances, CommitChangesToPrefFile can close the "TCP/IP Preferences"
- // file. The following is a hackaround to detect and safely fail in this case.
- // I haven't implemented the full workaround, which would be to walk the resource
- // chain looking to see whether my file has been closed because this problem should
- // never happen in practice.
-
- // My justification? Well, the code which accidentally closes
- // the "TCP/IP Preferences" file was added in Mac OS 8.5 as part of the "maintain
- // the DHCP lease over reboots" effort. But Mac OS 8.5 and up include the Network
- // Setup API, so you shouldn't be running this routine on those systems anyway.
- //
- // I only discovered this problem because I set kUseNetworkSetup to false to test
- // the "backward compatibility" code on an Mac OS 8.6 system.
- //
- // It turns out that Network Setup is bitten by this problem as well, but it's
- // less paranoid error checking fails to detect this case. I've filed a bug
- // to get OT fixed. [Radar ID 2354522]
-
- if (err == noErr) {
- if ( CurResFile() != refNum ) {
- MoreAssertQ(false);
- return -2;
- }
- }
-
- // Then reactive the TCP/IP stack, zeroing the 'dclt' preference in the process.
-
- // Re-get the 'unld' resource because the TCP/IP stack calls ReleaseResource
- // on it when it reconfigures.
-
- if (err == noErr) {
- unldResourceH = (OTCfgTCPUnloadAttr **) Get1Resource(kOTCfgTCPUnloadAttrPref, config);
- err = CheckResError(unldResourceH);
- }
- if (err == noErr && GetHandleSize( (Handle) unldResourceH) != sizeof(OTCfgTCPUnloadAttr)) {
- err = -1;
- }
- if (err == noErr) {
- **unldResourceH = oldUnloadAttr;
- ChangedResource( (Handle) unldResourceH);
- err = ResError();
- }
- if (err == noErr) {
- dcltResourceH = Get1Resource(kOTCfgTCPDHCPLeaseInfoPref, config);
- err = CheckResError(dcltResourceH);
- }
- if (err == noErr) {
-
- // In current OT builds, the 'dclt' preference is 16 bytes.
- // If this changes, we want to know about it.
- MoreAssertQ(GetHandleSize(dcltResourceH) == 16);
-
- MoreBlockZero(*dcltResourceH, GetHandleSize(dcltResourceH));
- ChangedResource(dcltResourceH);
- err = ResError();
- } else if (err == resNotFound) {
- err = noErr;
- }
- if (err == noErr) {
- UpdateResFile(refNum);
- err = ResError();
- }
- if (err == noErr) {
- err = CommitChangesToPrefFile(kOTCfgTypeTCPv4, refNum, config);
- }
-
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- return err;
- }
-
- extern pascal OSStatus NSHDHCPRelease(void)
- // See comments in interface part.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = DHCPReleaseDatabase();
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = DHCPReleaseFile();
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- AppleTalk On/Off using Database -----
-
- static OSStatus IsAppleTalkActiveDatabase(Boolean *active)
- // Implementation of NSHIsAppleTalkActive which uses the Network Setup
- // database. See NSHIsAppleTalkActive's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabaseRef ref;
- CfgEntityRef currentAppleTalkEntity;
- OTCfgATalkGeneral atpfPref;
-
- err = MNSOpenDatabase(&ref, false);
- if (err == noErr) {
- err = FindCurrentConnection(&ref, kOTCfgTypeAppleTalk, ¤tAppleTalkEntity);
- if (err == noErr) {
- err = MNSGetFixedSizePref(&ref, ¤tAppleTalkEntity, kOTCfgATalkGeneralPref, &atpfPref, sizeof(atpfPref));
- }
- if (err == noErr) {
- *active = (atpfPref.ddpPrefs.fLoadType != 0);
- }
-
- err2 = MNSCloseDatabase(&ref, false);
- if (err == noErr) {
- err = err2;
- }
- }
- return err;
- }
-
- static OSStatus SetAppleTalkActiveDatabase(Boolean active)
- // Implementation of NSHSetAppleTalkActive which uses the Network Setup
- // database. See NSHSetAppleTalkActive's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabaseRef ref;
- CfgEntityRef currentAppleTalkEntity;
- OTCfgATalkGeneral atpfPref;
- Boolean changeNeeded;
- UInt8 newValue;
-
- err = MNSOpenDatabase(&ref, true);
- if (err == noErr) {
- changeNeeded = true;
-
- err = FindCurrentConnection(&ref, kOTCfgTypeAppleTalk, ¤tAppleTalkEntity);
- if (err == noErr) {
- err = MNSGetFixedSizePref(&ref, ¤tAppleTalkEntity, kOTCfgATalkGeneralPref, &atpfPref, sizeof(atpfPref));
- }
- if (err == noErr) {
- if (active) {
- newValue = kOTCfgATalkActive;
- } else {
- newValue = kOTCfgATalkInactive;
- }
- changeNeeded = (newValue != atpfPref.ddpPrefs.fLoadType);
- if (changeNeeded) {
- atpfPref.ddpPrefs.fLoadType = newValue;
- err = MNSSetPref(&ref, ¤tAppleTalkEntity, kOTCfgATalkGeneralPref, &atpfPref, sizeof(atpfPref));
- }
- }
-
- err2 = MNSCloseDatabase(&ref, (err == noErr) && changeNeeded );
- if (err == noErr) {
- err = err2;
- }
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- AppleTalk On/Off using File -----
-
- static OSStatus IsAppleTalkActiveFile(Boolean *active)
- // Implementation of NSHIsAppleTalkActive which uses the legacy
- // preference files. See NSHIsAppleTalkActive's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- SInt16 oldResFile;
- SInt16 refNum;
- Handle atpfResource;
- SInt16 config;
-
- err = OpenNetworkPrefFile(kOTCfgTypeAppleTalk, fsRdPerm, &oldResFile, &refNum);
- if (err == noErr) {
- err = GetCurrentConfigFromPrefFile(&config);
-
- if (err == noErr) {
- atpfResource = Get1Resource(kOTCfgATalkGeneralPref, config);
- err = CheckResError(atpfResource);
- }
- if (err == noErr && GetHandleSize(atpfResource) != sizeof(OTCfgATalkGeneral)) {
- err = -1;
- }
- if (err == noErr) {
- *active = (**(OTCfgATalkGeneral **) atpfResource).ddpPrefs.fLoadType != 0;
- }
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- return err;
- }
-
- static OSStatus SetAppleTalkActiveFile(Boolean active)
- // Implementation of NSHSetAppleTalkActive which uses the legacy
- // preference files. See NSHSetAppleTalkActive's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- SInt16 refNum;
- SInt16 oldResFile;
- Handle atpfResource;
- SInt16 config;
- Boolean changeNeeded;
- UInt8 newValue;
-
- err = OpenNetworkPrefFile(kOTCfgTypeAppleTalk, fsRdWrPerm, &oldResFile, &refNum);
- if (err == noErr) {
- err = GetCurrentConfigFromPrefFile(&config);
-
- if (err == noErr) {
- atpfResource = Get1Resource(kOTCfgATalkGeneralPref, config);
- err = CheckResError(atpfResource);
- }
- if (err == noErr && GetHandleSize(atpfResource) != sizeof(OTCfgATalkGeneral)) {
- err = -1;
- }
- if (err == noErr) {
- if (active) {
- newValue = kOTCfgATalkActive;
- } else {
- newValue = kOTCfgATalkInactive;
- }
- changeNeeded = (newValue != (**(OTCfgATalkGeneral **) atpfResource).ddpPrefs.fLoadType);
- if (changeNeeded) {
- (**(OTCfgATalkGeneral **) atpfResource).ddpPrefs.fLoadType = newValue;
- ChangedResource(atpfResource);
- err = ResError();
- if (err == noErr) {
- UpdateResFile(refNum);
- err = ResError();
- }
- if (err == noErr) {
- err = CommitChangesToPrefFile(kOTCfgTypeAppleTalk, refNum, config);
- }
- }
- }
-
- err2 = CloseNetworkPrefFile(oldResFile, refNum);
- if (err == noErr) {
- err = err2;
- }
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- AppleTalk On/Off Abtraction -----
-
- extern pascal OSStatus NSHIsAppleTalkActive(Boolean *active)
- // See comments in interface part.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = IsAppleTalkActiveDatabase(active);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = IsAppleTalkActiveFile(active);
- }
- return err;
- }
-
- extern pascal OSStatus HSHSetAppleTalkActive(Boolean active)
- // See comments in interface part.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = SetAppleTalkActiveDatabase(active);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = SetAppleTalkActiveFile(active);
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Remote Access Password Encode -----
-
- static OSStatus EncodeRemotePasswordNetworkSetup(
- ConstStr255Param userName,
- ConstStr255Param password,
- Str255 encodedPassword)
- // Implementation of NSHEncodeRemotePassword which uses the Network Setup
- // routines added in Mac OS 9.0. See NSHEncodeRemotePassword's comment in
- // header file for interface specification.
- {
- MoreBlockZero(encodedPassword, sizeof(Str255));
- BlockMoveData(password + 1, encodedPassword, password[0]);
-
- (void) OTCfgEncrypt( (UInt8 *) userName, encodedPassword, sizeof(Str255));
-
- return noErr;
- }
-
- enum {
- _RemoteAccess = 0xAA5B
- };
-
- static OSStatus EncodeRemotePasswordARA(
- ConstStr255Param userName,
- ConstStr255Param password,
- Str255 encodedPassword)
- // Implementation of NSHEncodeRemotePassword which uses the ARA 2.x
- // API (which is also emulated by ARA 3.x). See NSHEncodeRemotePassword's
- // comment in header file for interface specification.
- {
- OSStatus err;
- TRemoteAccessPasswordMunger pb;
- UInt8 chunkOfPassword[9];
- ByteCount offset;
-
- // Only call PBRemoteAccess if it's implemented!
-
- err = unimpErr;
- if ( GetToolboxTrapAddress(_RemoteAccess) != GetToolboxTrapAddress(_Unimplemented) ) {
- // Zero the encoded password buffer and copy the
- // password (sans length byte) into it.
-
- OTMemzero(encodedPassword, sizeof(Str255));
- BlockMoveData(&password[1], encodedPassword, password[0]);
-
- // Now walk through the password in chunks, copying
- // a chunk into the chunkOfPassword buffer, encrypting
- // that buffer with the ARA API, and then copying the
- // buffer back out to the encrypted password.
-
- // Note that the for loop increments offset by 8 each time.
-
- for (offset = 0; offset < 256 ; offset += 8) {
-
- // Copy a chunk of the password into chunkOfPassword.
-
- BlockMoveData(encodedPassword + offset, &chunkOfPassword[1], 8);
- chunkOfPassword[0] = 8;
-
- // Setup the parameter block for a remote access API call.
-
- pb.csCode = RAM_EXTENDED_CALL;
- pb.resultStrPtr = nil;
- pb.extendedType = (char*) REMOTEACCESSNAME;
- pb.extendedCode = CmdRemoteAccess_PassWordMunger;
- pb.userNamePtr = (UInt8 *) userName;
- pb.passWordPtr = chunkOfPassword;
- pb.reserved = 0;
-
- err = MorePBRemoteAccess((TPRemoteAccessParamBlock) &pb, false);
- if (err == noErr) {
- err = pb.ioResult;
- }
- if (err == noErr) {
-
- // Copy the encrypted chunk of password back out into
- // encodedPassword.
-
- BlockMoveData(&chunkOfPassword[1], encodedPassword + offset, 8);
- } else {
- break;
- }
- }
-
- // Tidy up encoded password. Move the encrypted data up
- // one byte and insert a zero length byte. Don't ask me
- // why this is required, I didn't invent this scheme (-:
-
- BlockMoveData(encodedPassword, encodedPassword + 1, sizeof(Str255) - 1);
- encodedPassword[0] = 0;
- }
-
- return err;
- }
-
- extern pascal OSStatus NSHEncodeRemotePassword(
- ConstStr255Param userName,
- ConstStr255Param password,
- Str255 encodedPassword)
- // See comments in interface part.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- if ( (void *) OTCfgEncrypt != (void *) kUnresolvedCFragSymbolAddress ) {
- err = EncodeRemotePasswordNetworkSetup(userName, password, encodedPassword);
- } else
- #endif
- {
- err = EncodeRemotePasswordARA(userName, password, encodedPassword);
- }
- } else {
- err = EncodeRemotePasswordARA(userName, password, encodedPassword);
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
-